diff --git a/.github/build.in.yml b/.github/build.in.yml index 141b5316926ab..c56faf4061fea 100644 --- a/.github/build.in.yml +++ b/.github/build.in.yml @@ -127,16 +127,6 @@ jobs: run: | lake build cache - - name: prune ProofWidgets .lake - run: | - lake build proofwidgets:release - # 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 id: get run: | @@ -250,7 +240,7 @@ jobs: - name: check declarations in db files run: | - python3 scripts/yaml_check.py docs/100.yaml docs/overview.yaml docs/undergrad.yaml + python3 scripts/yaml_check.py docs/100.yaml docs/1000.yaml docs/overview.yaml docs/undergrad.yaml lake exe check-yaml - name: generate our import graph diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4e43547be01ea..79181e47c2b08 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,8 @@ version: 2 # Specifies the version of the Dependabot configuration file format updates: # Configuration for dependency updates - package-ecosystem: "github-actions" # Specifies the ecosystem to check for updates - directory: "/" # Specifies the directory to check for dependencies; "/" means the root directory + directories: + - "/.github/*" # covers `build.in.yml` as well, which is not in `.github/workflows/` because it shouldn't be run in CI. schedule: # Check for updates to GitHub Actions every month interval: "monthly" diff --git a/.github/workflows/bors.yml b/.github/workflows/bors.yml index 3bd02efbb94dd..869b4d379c959 100644 --- a/.github/workflows/bors.yml +++ b/.github/workflows/bors.yml @@ -137,16 +137,6 @@ jobs: run: | lake build cache - - name: prune ProofWidgets .lake - run: | - lake build proofwidgets:release - # 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 id: get run: | @@ -260,7 +250,7 @@ jobs: - name: check declarations in db files run: | - python3 scripts/yaml_check.py docs/100.yaml docs/overview.yaml docs/undergrad.yaml + python3 scripts/yaml_check.py docs/100.yaml docs/1000.yaml docs/overview.yaml docs/undergrad.yaml lake exe check-yaml - name: generate our import graph diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b5f11a1ea1f03..25c242698e644 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -144,16 +144,6 @@ jobs: run: | lake build cache - - name: prune ProofWidgets .lake - run: | - lake build proofwidgets:release - # 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 id: get run: | @@ -267,7 +257,7 @@ jobs: - name: check declarations in db files run: | - python3 scripts/yaml_check.py docs/100.yaml docs/overview.yaml docs/undergrad.yaml + python3 scripts/yaml_check.py docs/100.yaml docs/1000.yaml docs/overview.yaml docs/undergrad.yaml lake exe check-yaml - name: generate our import graph diff --git a/.github/workflows/build_fork.yml b/.github/workflows/build_fork.yml index 4da591010b8b7..9848f1817b72d 100644 --- a/.github/workflows/build_fork.yml +++ b/.github/workflows/build_fork.yml @@ -141,16 +141,6 @@ jobs: run: | lake build cache - - name: prune ProofWidgets .lake - run: | - lake build proofwidgets:release - # 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 id: get run: | @@ -264,7 +254,7 @@ jobs: - name: check declarations in db files run: | - python3 scripts/yaml_check.py docs/100.yaml docs/overview.yaml docs/undergrad.yaml + python3 scripts/yaml_check.py docs/100.yaml docs/1000.yaml docs/overview.yaml docs/undergrad.yaml lake exe check-yaml - name: generate our import graph diff --git a/.github/workflows/discover-lean-pr-testing.yml b/.github/workflows/discover-lean-pr-testing.yml index fa3dcad9ae5fe..0abbbef132b36 100644 --- a/.github/workflows/discover-lean-pr-testing.yml +++ b/.github/workflows/discover-lean-pr-testing.yml @@ -124,6 +124,22 @@ jobs: echo "branches_exist=true" >> "$GITHUB_ENV" fi + - name: Prepare Zulip message + id: zulip-message + run: | + BRANCHES="${{ steps.find-branches.outputs.branches }}" + { + printf "msg<> "$GITHUB_OUTPUT" + - name: Send message on Zulip if: env.branches_exist == 'true' uses: zulip/github-actions-zulip/send-message@v1 @@ -133,8 +149,6 @@ jobs: organization-url: 'https://leanprover.zulipchat.com' to: 'nightly-testing' type: 'stream' - topic: 'Mathlib status updates' + topic: 'Mergeable lean testing PRs' content: | - We will need to merge the following branches into `nightly-testing`: - - ${{ steps.find-branches.outputs.branches }} + ${{ steps.zulip-message.outputs.msg }} diff --git a/.github/workflows/lean4checker.yml b/.github/workflows/lean4checker.yml index 066648826282a..c521c9164c994 100644 --- a/.github/workflows/lean4checker.yml +++ b/.github/workflows/lean4checker.yml @@ -1,4 +1,3 @@ -# https://chat.openai.com/share/26102e95-ac9c-4d03-a000-73e4f6cee8cd name: lean4checker Workflow on: @@ -6,14 +5,19 @@ on: - cron: '0 0 * * *' # Runs at 00:00 UTC every day workflow_dispatch: +env: + DEFAULT_BRANCH: master + TAG_PATTERN: '^nightly-testing-[0-9]{4}-[0-9]{2}-[0-9]{2}$' + jobs: check-lean4checker: - runs-on: pr + runs-on: ubuntu-latest + strategy: + matrix: + branch_type: [master, nightly] steps: - - - name: cleanup + - name: Cleanup run: | - find . -name . -o -prune -exec rm -rf -- {} + # Delete all but the 5 most recent toolchains. # Make sure to delete both the `~/.elan/toolchains/X` directory and the `~/.elan/update-hashes/X` file. # Skip symbolic links (`-type d`), the current directory (`! -name .`), and `nightly` and `stable`. @@ -23,21 +27,24 @@ jobs: : # Do nothing on failure, but suppress errors fi - # The Hoskinson runners may not have jq installed, so do that now. - - name: 'Setup jq' - uses: dcarbone/install-jq-action@v2.1.0 - - - name: install elan + - name: Install elan run: | set -o pipefail curl -sSfL https://github.com/leanprover/elan/releases/download/v3.1.1/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz ./elan-init -y --default-toolchain none echo "$HOME/.elan/bin" >> "${GITHUB_PATH}" - - name: Checkout master branch + - name: Fetch latest tags (if nightly) + if: matrix.branch_type == 'nightly' + run: | + git fetch --tags + LATEST_TAG=$(git tag | grep -E "${{ env.TAG_PATTERN }}" | sort -r | head -n 1) + echo "LATEST_TAG=${LATEST_TAG}" >> "$GITHUB_ENV" + + - name: Checkout branch or tag uses: actions/checkout@v4 with: - ref: 'master' + ref: ${{ matrix.branch_type == 'master' && env.DEFAULT_BRANCH || env.LATEST_TAG }} - name: If using a lean-pr-release toolchain, uninstall run: | @@ -46,7 +53,7 @@ jobs: elan toolchain uninstall "$(cat lean-toolchain)" fi - - name: print lean and lake versions + - name: Print Lean and Lake versions run: | lean --version lake --version @@ -55,16 +62,6 @@ jobs: run: | lake exe cache get - - 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 - lake build ProofWidgets - - name: Check environments using lean4checker id: lean4checker run: | @@ -100,7 +97,7 @@ jobs: type: 'stream' topic: 'lean4checker' content: | - ✅ lean4checker [succeeded](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} + ✅ lean4checker [succeeded](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} (branch: ${{ matrix.branch_type == 'master' && 'master' || env.LATEST_TAG }}) - name: Post failure message on Zulip if: failure() @@ -113,7 +110,7 @@ jobs: type: 'stream' topic: 'lean4checker failure' content: | - ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} + ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} (branch: ${{ matrix.branch_type == 'master' && 'master' || env.LATEST_TAG }}) continue-on-error: true - name: Post failure message on Zulip main topic @@ -127,5 +124,5 @@ jobs: type: 'stream' topic: 'lean4checker' content: | - ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} + ❌ lean4checker [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) on ${{ github.sha }} (branch: ${{ matrix.branch_type == 'master' && 'master' || env.LATEST_TAG }}) continue-on-error: true diff --git a/.github/workflows/nightly_detect_failure.yml b/.github/workflows/nightly_detect_failure.yml index 0f52fa1c48fc2..b37d8c9217e53 100644 --- a/.github/workflows/nightly_detect_failure.yml +++ b/.github/workflows/nightly_detect_failure.yml @@ -51,7 +51,7 @@ jobs: git tag "nightly-testing-${version}" git push origin "nightly-testing-${version}" hash="$(git rev-parse "nightly-testing-${version}")" - curl -X POST "http://speed.lean-fro.org/mathlib4/api/queue/commit/e7b27246-a3e6-496a-b552-ff4b45c7236e/$hash" -u "admin:${{ secrets.SPEED }}" + curl -X POST "https://speed.lean-lang.org/mathlib4/api/queue/commit/e7b27246-a3e6-496a-b552-ff4b45c7236e/$hash" -u "admin:${{ secrets.SPEED }}" fi hash="$(git rev-parse "nightly-testing-${version}")" printf 'SHA=%s\n' "${hash}" >> "${GITHUB_ENV}" diff --git a/.github/workflows/zulip_emoji_awaiting_author.yaml b/.github/workflows/zulip_emoji_awaiting_author.yaml new file mode 100644 index 0000000000000..e3f57ab9cfc82 --- /dev/null +++ b/.github/workflows/zulip_emoji_awaiting_author.yaml @@ -0,0 +1,34 @@ +on: + pull_request: + types: [labeled, unlabeled] +jobs: + set_pr_emoji: + if: github.event.label.name == 'awaiting-author' + runs-on: ubuntu-latest + steps: + - name: Checkout mathlib repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + scripts/zulip_emoji_merge_delegate.py + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install zulip + + - name: Add or remove emoji + env: + ZULIP_API_KEY: ${{ secrets.ZULIP_API_KEY }} + ZULIP_EMAIL: github-mathlib4-bot@leanprover.zulipchat.com + ZULIP_SITE: https://leanprover.zulipchat.com + PR_NUMBER: ${{ github.event.number}} + LABEL_STATUS: ${{ github.event.action }} + run: | + printf $'Running the python script with pr "%s"\n' "$PR_NUMBER" + python scripts/zulip_emoji_merge_delegate.py "$ZULIP_API_KEY" "$ZULIP_EMAIL" "$ZULIP_SITE" "$LABEL_STATUS" "$PR_NUMBER" diff --git a/Archive/Imo/Imo1964Q1.lean b/Archive/Imo/Imo1964Q1.lean index dda0e7f1e11cb..6a3e8cba29dfd 100644 --- a/Archive/Imo/Imo1964Q1.lean +++ b/Archive/Imo/Imo1964Q1.lean @@ -5,25 +5,17 @@ Authors: Kevin Buzzard -/ import Mathlib.Tactic.IntervalCases import Mathlib.Data.Nat.ModEq -import Mathlib.Tactic.Ring /-! # IMO 1964 Q1 (a) Find all positive integers $n$ for which $2^n-1$ is divisible by $7$. - (b) Prove that there is no positive integer $n$ for which $2^n+1$ is divisible by $7$. -We define a predicate for the solutions in (a), and prove that it is the set of positive -integers which are a multiple of 3. --/ - - -/-! -## Intermediate lemmas +For (a), we find that the order of $2$ mod $7$ is $3$. Therefore for (b), it suffices to check +$n = 0, 1, 2$. -/ - open Nat namespace Imo1964Q1 @@ -33,17 +25,13 @@ theorem two_pow_mod_seven (n : ℕ) : 2 ^ n ≡ 2 ^ (n % 3) [MOD 7] := calc 2 ^ n = 2 ^ (3 * (n / 3) + t) := by rw [Nat.div_add_mod] _ = (2 ^ 3) ^ (n / 3) * 2 ^ t := by rw [pow_add, pow_mul] _ ≡ 1 ^ (n / 3) * 2 ^ t [MOD 7] := by gcongr; decide - _ = 2 ^ t := by ring - -/-! -## The question --/ + _ = 2 ^ t := by rw [one_pow, one_mul] +end Imo1964Q1 -def ProblemPredicate (n : ℕ) : Prop := - 7 ∣ 2 ^ n - 1 +open Imo1964Q1 -theorem imo1964_q1a (n : ℕ) (_ : 0 < n) : ProblemPredicate n ↔ 3 ∣ n := by +theorem imo1964_q1a (n : ℕ) (_ : 0 < n) : 7 ∣ 2 ^ n - 1 ↔ 3 ∣ n := by let t := n % 3 have : t < 3 := Nat.mod_lt _ (by decide) calc 7 ∣ 2 ^ n - 1 ↔ 2 ^ n ≡ 1 [MOD 7] := by @@ -53,15 +41,11 @@ theorem imo1964_q1a (n : ℕ) (_ : 0 < n) : ProblemPredicate n ↔ 3 ∣ n := by _ ↔ t = 0 := by interval_cases t <;> decide _ ↔ 3 ∣ n := by rw [dvd_iff_mod_eq_zero] -end Imo1964Q1 - -open Imo1964Q1 - theorem imo1964_q1b (n : ℕ) : ¬7 ∣ 2 ^ n + 1 := by intro h let t := n % 3 have : t < 3 := Nat.mod_lt _ (by decide) have H : 2 ^ t + 1 ≡ 0 [MOD 7] := calc - 2 ^ t + 1 ≡ 2 ^ n + 1 [MOD 7 ] := by gcongr ?_ + 1; exact (two_pow_mod_seven n).symm + 2 ^ t + 1 ≡ 2 ^ n + 1 [MOD 7] := by gcongr ?_ + 1; exact (two_pow_mod_seven n).symm _ ≡ 0 [MOD 7] := h.modEq_zero_nat interval_cases t <;> contradiction diff --git a/Archive/Imo/Imo1972Q5.lean b/Archive/Imo/Imo1972Q5.lean index ba2e4d8c6a0a0..75a0cc13edea4 100644 --- a/Archive/Imo/Imo1972Q5.lean +++ b/Archive/Imo/Imo1972Q5.lean @@ -80,11 +80,10 @@ This is a more concise version of the proof proposed by Ruben Van de Velde. -/ theorem imo1972_q5' (f g : ℝ → ℝ) (hf1 : ∀ x, ∀ y, f (x + y) + f (x - y) = 2 * f x * g y) (hf2 : BddAbove (Set.range fun x => ‖f x‖)) (hf3 : ∃ x, f x ≠ 0) (y : ℝ) : ‖g y‖ ≤ 1 := by - -- Porting note: moved `by_contra!` up to avoid a bug - by_contra! H obtain ⟨x, hx⟩ := hf3 set k := ⨆ x, ‖f x‖ have h : ∀ x, ‖f x‖ ≤ k := le_ciSup hf2 + by_contra! H have hgy : 0 < ‖g y‖ := by linarith have k_pos : 0 < k := lt_of_lt_of_le (norm_pos_iff.mpr hx) (h x) have : k / ‖g y‖ < k := (div_lt_iff₀ hgy).mpr (lt_mul_of_one_lt_right k_pos H) diff --git a/Archive/Imo/Imo2013Q1.lean b/Archive/Imo/Imo2013Q1.lean index 295886d7e18ea..6cd9697d983b5 100644 --- a/Archive/Imo/Imo2013Q1.lean +++ b/Archive/Imo/Imo2013Q1.lean @@ -27,7 +27,6 @@ We prove a slightly more general version where k does not need to be strictly po namespace Imo2013Q1 --- Porting note: simplified proof using `positivity` theorem arith_lemma (k n : ℕ) : 0 < 2 * n + 2 ^ k.succ := by positivity theorem prod_lemma (m : ℕ → ℕ+) (k : ℕ) (nm : ℕ+) : diff --git a/Archive/Imo/Imo2019Q4.lean b/Archive/Imo/Imo2019Q4.lean index fe10780d6586f..1bcfbe0c77878 100644 --- a/Archive/Imo/Imo2019Q4.lean +++ b/Archive/Imo/Imo2019Q4.lean @@ -30,7 +30,7 @@ open scoped Nat open Nat hiding zero_le Prime -open Finset multiplicity +open Finset namespace Imo2019Q4 diff --git a/Archive/Imo/Imo2024Q5.lean b/Archive/Imo/Imo2024Q5.lean index 5cbdf23de02f8..4fa8394b08d3d 100644 --- a/Archive/Imo/Imo2024Q5.lean +++ b/Archive/Imo/Imo2024Q5.lean @@ -229,7 +229,7 @@ lemma find?_eq_eq_find?_le {l : List (Cell N)} {r : Fin (N + 2)} (hne : l ≠ [] by_cases h : head.1 = r · simp [h] · have h' : ¬(r ≤ head.1) := fun hr' ↦ h (le_antisymm hf hr') - simp only [h, decide_False, Bool.false_eq_true, not_false_eq_true, List.find?_cons_of_neg, h'] + simp only [h, decide_false, Bool.false_eq_true, not_false_eq_true, List.find?_cons_of_neg, h'] rcases tail with ⟨⟩ | ⟨htail, ttail⟩ · simp · simp only [List.chain'_cons] at ha @@ -315,7 +315,7 @@ lemma Path.tail_findFstEq (p : Path N) {r : Fin (N + 2)} (hr : r ≠ 0) : rcases cells with ⟨⟩ | ⟨head, tail⟩ · simp at nonempty · simp only [List.head_cons] at head_first_row - simp only [List.find?_cons, head_first_row, hr.symm, decide_False] + simp only [List.find?_cons, head_first_row, hr.symm, decide_false] rfl · simp_rw [Path.tail, if_neg h] @@ -329,7 +329,7 @@ lemma Path.tail_firstMonster (p : Path N) (m : MonsterData N) : · simp at nonempty · simp only [List.head_cons] at head_first_row simp only [List.find?_cons, head_first_row, - m.not_mem_monsterCells_of_fst_eq_zero head_first_row, decide_False] + m.not_mem_monsterCells_of_fst_eq_zero head_first_row, decide_false] rfl · simp_rw [Path.tail, if_neg h] @@ -352,17 +352,17 @@ lemma Path.firstMonster_eq_of_findFstEq_mem {p : Path N} {m : MonsterData N} · simp only [List.head_cons] at head_first_row simp only [List.getElem_cons_succ] at h1 simp only [List.length_cons, lt_add_iff_pos_left, List.length_pos_iff_ne_nil] at hl - simp only [m.not_mem_monsterCells_of_fst_eq_zero head_first_row, decide_False, + simp only [m.not_mem_monsterCells_of_fst_eq_zero head_first_row, decide_false, Bool.false_eq_true, not_false_eq_true, List.find?_cons_of_neg, head_first_row, Fin.zero_eq_one_iff, Nat.reduceEqDiff, Option.some_get] - simp only [findFstEq, head_first_row, Fin.zero_eq_one_iff, Nat.reduceEqDiff, decide_False, + simp only [findFstEq, head_first_row, Fin.zero_eq_one_iff, Nat.reduceEqDiff, decide_false, Bool.false_eq_true, not_false_eq_true, List.find?_cons_of_neg] at h rcases tail with ⟨⟩ | ⟨htail, ttail⟩ · simp at hl · simp only [List.getElem_cons_zero] at h1 have h1' : htail.1 = 1 := by simp [Fin.ext_iff, h1] - simp only [h1', decide_True, List.find?_cons_of_pos, Option.get_some] at h - simp only [h1', h, decide_True, List.find?_cons_of_pos] + simp only [h1', decide_true, List.find?_cons_of_pos, Option.get_some] at h + simp only [h1', h, decide_true, List.find?_cons_of_pos] case ind p ht => have h1 : (1 : Fin (N + 2)) ≠ 0 := by simp rw [p.tail_findFstEq h1, p.tail_firstMonster m] at ht diff --git a/Archive/MiuLanguage/Basic.lean b/Archive/MiuLanguage/Basic.lean index 1b1ac4a10368e..722c0eeebd657 100644 --- a/Archive/MiuLanguage/Basic.lean +++ b/Archive/MiuLanguage/Basic.lean @@ -106,9 +106,7 @@ instance : Repr MiuAtom := /-- For simplicity, an `Miustr` is just a list of elements of type `MiuAtom`. -/ -def Miustr := - List MiuAtom -deriving Append +abbrev Miustr := List MiuAtom instance : Membership MiuAtom Miustr := by unfold Miustr; infer_instance diff --git a/Archive/MiuLanguage/DecisionNec.lean b/Archive/MiuLanguage/DecisionNec.lean index 3bd06ca5463c6..e9c3d760485de 100644 --- a/Archive/MiuLanguage/DecisionNec.lean +++ b/Archive/MiuLanguage/DecisionNec.lean @@ -154,9 +154,7 @@ theorem goodm_of_rule3 (as bs : Miustr) (h₁ : Derivable (as ++ ↑[I, I, I] ++ exact mhead · contrapose! nmtail rcases exists_cons_of_ne_nil k with ⟨x, xs, rfl⟩ - -- Porting note: `simp_rw [cons_append]` didn't work - rw [cons_append] at nmtail; rw [cons_append, cons_append] - dsimp only [tail] at nmtail ⊢ + simp_rw [cons_append] at nmtail ⊢ simpa using nmtail /-! @@ -174,9 +172,7 @@ theorem goodm_of_rule4 (as bs : Miustr) (h₁ : Derivable (as ++ ↑[U, U] ++ bs exact mhead · contrapose! nmtail rcases exists_cons_of_ne_nil k with ⟨x, xs, rfl⟩ - -- Porting note: `simp_rw [cons_append]` didn't work - rw [cons_append] at nmtail; rw [cons_append, cons_append] - dsimp only [tail] at nmtail ⊢ + simp_rw [cons_append] at nmtail ⊢ simpa using nmtail /-- Any derivable string must begin with `M` and have no `M` in its tail. diff --git a/Archive/MiuLanguage/DecisionSuf.lean b/Archive/MiuLanguage/DecisionSuf.lean index 2f1f8bbf87750..4313004779cb8 100644 --- a/Archive/MiuLanguage/DecisionSuf.lean +++ b/Archive/MiuLanguage/DecisionSuf.lean @@ -308,10 +308,8 @@ theorem ind_hyp_suf (k : ℕ) (ys : Miustr) (hu : count U ys = succ k) (hdec : D rcases eq_append_cons_U_of_count_U_pos hu with ⟨as, bs, rfl⟩ use as, bs refine ⟨rfl, ?_, ?_, ?_⟩ - · -- Porting note: `simp_rw [count_append]` didn't work - rw [count_append] at hu - simp_rw [count_cons, beq_self_eq_true, if_true, add_succ, beq_iff_eq, reduceCtorEq, reduceIte, - add_zero, succ_inj'] at hu + · simp_rw [count_append, count_cons, beq_self_eq_true, if_true, add_succ, beq_iff_eq, + reduceCtorEq, reduceIte, add_zero, succ_inj'] at hu rwa [count_append, count_append] · apply And.intro rfl rw [cons_append, cons_append] diff --git a/Archive/Wiedijk100Theorems/PerfectNumbers.lean b/Archive/Wiedijk100Theorems/PerfectNumbers.lean index a97ff90b5c744..d9d5bb09b3335 100644 --- a/Archive/Wiedijk100Theorems/PerfectNumbers.lean +++ b/Archive/Wiedijk100Theorems/PerfectNumbers.lean @@ -55,7 +55,7 @@ theorem even_two_pow_mul_mersenne_of_prime (k : ℕ) (pr : (mersenne (k + 1)).Pr Even (2 ^ k * mersenne (k + 1)) := by simp [ne_zero_of_prime_mersenne k pr, parity_simps] theorem eq_two_pow_mul_odd {n : ℕ} (hpos : 0 < n) : ∃ k m : ℕ, n = 2 ^ k * m ∧ ¬Even m := by - have h := Nat.multiplicity_finite_iff.2 ⟨Nat.prime_two.ne_one, hpos⟩ + have h := Nat.finiteMultiplicity_iff.2 ⟨Nat.prime_two.ne_one, hpos⟩ cases' pow_multiplicity_dvd 2 n with m hm use multiplicity 2 n, m refine ⟨hm, ?_⟩ diff --git a/Cache/Requests.lean b/Cache/Requests.lean index 295d65cd96693..38f3db11e9406 100644 --- a/Cache/Requests.lean +++ b/Cache/Requests.lean @@ -161,14 +161,27 @@ into the `lean-toolchain` file at the root directory of your project" /-- Fetches the ProofWidgets cloud release and prunes non-JS files. -/ def getProofWidgets (buildDir : FilePath) : IO Unit := do - if (← buildDir.pathExists) then return - -- Unpack the ProofWidgets cloud release (for its `.js` files) + if (← buildDir.pathExists) then + -- Check if the ProofWidgets build is out-of-date via `lake`. + -- This is done through Lake as cache has no simple heuristic + -- to determine whether the ProofWidgets JS is out-of-date. + let exitCode ← (← IO.Process.spawn {cmd := "lake", args := #["-q", "build", "--no-build", "proofwidgets:release"]}).wait + if exitCode == 0 then -- up-to-date + return + else if exitCode == 3 then -- needs fetch (`--no-build` triggered) + pure () + else + throw <| IO.userError s!"Failed to validate ProofWidgets cloud release: lake failed with error code {exitCode}" + -- Download and unpack the ProofWidgets cloud release (for its `.js` files) let exitCode ← (← IO.Process.spawn {cmd := "lake", args := #["-q", "build", "proofwidgets:release"]}).wait if exitCode != 0 then throw <| IO.userError s!"Failed to fetch ProofWidgets cloud release: lake failed with error code {exitCode}" - -- prune non-js ProofWidgets files (e.g., `olean`, `.c`) - IO.FS.removeDirAll (buildDir / "lib") - IO.FS.removeDirAll (buildDir / "ir") + -- Prune non-JS ProofWidgets files (e.g., `olean`, `.c`) + try + IO.FS.removeDirAll (buildDir / "lib") + IO.FS.removeDirAll (buildDir / "ir") + catch e => + throw <| IO.userError s!"Failed to prune ProofWidgets cloud release: {e}" /-- Downloads missing files, and unpacks files. -/ def getFiles (hashMap : IO.HashMap) (forceDownload forceUnpack parallel decompress : Bool) : diff --git a/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean index 832f9e8bef97d..b2961dcf17622 100644 --- a/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean +++ b/Counterexamples/CanonicallyOrderedCommSemiringTwoMul.lean @@ -101,8 +101,7 @@ theorem mul_lt_mul_of_pos_right : ∀ a b c : ℕ × ZMod 2, a < b → 0 < c → instance socsN2 : StrictOrderedCommSemiring (ℕ × ZMod 2) := { Nxzmod2.csrN21, (inferInstance : PartialOrder (ℕ × ZMod 2)), (inferInstance : CommSemiring (ℕ × ZMod 2)), - pullback_nonzero Prod.fst Prod.fst_zero - Prod.fst_one with + domain_nontrivial Prod.fst Prod.fst_zero Prod.fst_one with add_le_add_left := add_le_add_left le_of_add_le_add_left := le_of_add_le_add_left zero_le_one := zero_le_one diff --git a/Counterexamples/HomogeneousPrimeNotPrime.lean b/Counterexamples/HomogeneousPrimeNotPrime.lean index 1499232c5f88f..61c133a80e292 100644 --- a/Counterexamples/HomogeneousPrimeNotPrime.lean +++ b/Counterexamples/HomogeneousPrimeNotPrime.lean @@ -110,13 +110,8 @@ theorem grading.right_inv : Function.RightInverse (coeLinearMap (grading R)) gra induction' zz using DirectSum.induction_on with i zz d1 d2 ih1 ih2 · simp only [map_zero] · rcases i with (_ | ⟨⟨⟩⟩) <;> rcases zz with ⟨⟨a, b⟩, hab : _ = _⟩ <;> dsimp at hab <;> - cases hab <;> - -- Porting note: proof was `decide` - -- now we need a `simp` and two `erw` subproofs... - simp only [coeLinearMap_of, decompose, AddMonoidHom.coe_mk, - ZeroHom.coe_mk, sub_self, sub_zero] - · erw [map_zero (of (grading R ·) 1), add_zero]; rfl - · erw [map_zero (of (grading R ·) 0), zero_add]; rfl + -- Porting note: proof was `decide` (without reverting any free variables). + cases hab <;> decide +revert · simp only [map_add, ih1, ih2] theorem grading.left_inv : Function.LeftInverse (coeLinearMap (grading R)) grading.decompose := diff --git a/Counterexamples/Pseudoelement.lean b/Counterexamples/Pseudoelement.lean index af58937a6308c..46052cc97e77a 100644 --- a/Counterexamples/Pseudoelement.lean +++ b/Counterexamples/Pseudoelement.lean @@ -74,26 +74,24 @@ theorem x_not_pseudo_eq : ¬PseudoEqual _ x y := by replace h := ModuleCat.eq_range_of_pseudoequal h dsimp [x, y] at h let φ := biprod.lift (𝟙 (of ℤ ℚ)) (2 • 𝟙 (of ℤ ℚ)) - have mem_range := mem_range_self φ (1 : ℚ) + have mem_range := mem_range_self φ.hom (1 : ℚ) rw [h] at mem_range obtain ⟨a, ha⟩ := mem_range - erw [← ModuleCat.id_apply (φ (1 : ℚ)), ← biprod.total, ← LinearMap.comp_apply, ← comp_def, - Preadditive.comp_add] at ha + rw [← ModuleCat.id_apply _ (φ (1 : ℚ)), ← biprod.total, ← LinearMap.comp_apply, + ← ModuleCat.hom_comp, Preadditive.comp_add] at ha let π₁ := (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) have ha₁ := congr_arg π₁ ha - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] at ha₁ + rw [← ModuleCat.comp_apply, ← ModuleCat.comp_apply] at ha₁ simp only [π₁, φ, BinaryBiproduct.bicone_fst, biprod.lift_fst, CategoryTheory.id_apply, biprod.lift_fst_assoc, Category.id_comp, biprod.lift_snd_assoc, Linear.smul_comp, Preadditive.add_comp, BinaryBicone.inl_fst, BinaryBicone.inr_fst, smul_zero, add_zero] at ha₁ let π₂ := (biprod.snd : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) have ha₂ := congr_arg π₂ ha - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [← CategoryTheory.comp_apply, ← CategoryTheory.comp_apply] at ha₂ + rw [← ModuleCat.comp_apply, ← ModuleCat.comp_apply] at ha₂ simp only [π₁, π₂, φ, BinaryBiproduct.bicone_snd, biprod.lift_snd, CategoryTheory.id_apply, biprod.lift_fst_assoc, Category.id_comp, biprod.lift_snd_assoc, Linear.smul_comp, Preadditive.add_comp, BinaryBicone.inl_snd, BinaryBicone.inr_snd, zero_add, two_smul] at ha₂ - erw [add_apply, CategoryTheory.id_apply] at ha₂ + erw [add_apply, ModuleCat.id_apply] at ha₂ subst ha₁ simp only [self_eq_add_right] at ha₂ exact one_ne_zero' ℚ ha₂ @@ -104,12 +102,12 @@ open scoped Pseudoelement /-- `biprod.fst ⟦x⟧ = biprod.fst ⟦y⟧`. -/ theorem fst_mk'_x_eq_fst_mk'_y : - (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) ⟦x⟧ = (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) ⟦y⟧ := + pseudoApply biprod.fst ⟦x⟧ = pseudoApply biprod.fst ⟦y⟧ := Quotient.eq.2 fst_x_pseudo_eq_fst_y /-- `biprod.snd ⟦x⟧ = biprod.snd ⟦y⟧`. -/ theorem snd_mk'_x_eq_snd_mk'_y : - (biprod.snd : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) ⟦x⟧ = (biprod.snd : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) ⟦y⟧ := + pseudoApply biprod.snd ⟦x⟧ = pseudoApply biprod.snd ⟦y⟧ := Quotient.eq.2 snd_x_pseudo_eq_snd_y -- Porting note: needs explicit type ascription `: Quotient <| Pseudoelement.setoid _` @@ -125,8 +123,8 @@ theorem exist_ne_and_fst_eq_fst_and_snd_eq_snd : ∃ x y, -- Porting note: removed type ascription `: of ℤ ℚ ⊞ of ℤ ℚ`, it gave an error about -- `Type` not having zero morphisms. jmc: I don't understand where the error came from x ≠ y ∧ - (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) x = (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) y ∧ - (biprod.snd : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) x = (biprod.snd : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) y := + pseudoApply (biprod.fst : of ℤ ℚ ⊞ of ℤ ℚ ⟶ _) x = pseudoApply biprod.fst y ∧ + pseudoApply biprod.snd x = pseudoApply biprod.snd y := ⟨⟦x⟧, ⟦y⟧, mk'_x_ne_mk'_y, fst_mk'_x_eq_fst_mk'_y, snd_mk'_x_eq_snd_mk'_y⟩ end diff --git a/LongestPole/Main.lean b/LongestPole/Main.lean index 0ab7b0d3148a6..102f398c4acf7 100644 --- a/LongestPole/Main.lean +++ b/LongestPole/Main.lean @@ -34,7 +34,7 @@ def mathlib4RepoId : String := "e7b27246-a3e6-496a-b552-ff4b45c7236e" namespace SpeedCenterAPI def runJson (hash : String) (repoId : String := mathlib4RepoId) : IO String := - runCurl #[s!"http://speed.lean-fro.org/mathlib4/api/run/{repoId}?hash={hash}"] + runCurl #[s!"https://speed.lean-lang.org/mathlib4/api/run/{repoId}?hash={hash}"] def getRunResponse (hash : String) : IO RunResponse := do let r ← runJson hash @@ -44,7 +44,7 @@ def getRunResponse (hash : String) : IO RunResponse := do | .ok v => pure v | .error e => match fromJson? j with | .ok (v : ErrorMessage) => - IO.eprintln s!"http://speed.lean-fro.org says: {v.message}" + IO.eprintln s!"https://speed.lean-lang.org says: {v.message}" IO.eprintln s!"Try moving to an older commit?" IO.Process.exit 1 | .error _ => throw <| IO.userError s!"Could not parse speed center JSON: {e}\n{j}" @@ -135,6 +135,8 @@ def longestPoleCLI (args : Cli.Parsed) : IO UInt32 := do | some to => pure <| to.as! ModuleName | none => ImportGraph.getCurrentModule -- autodetect the main module from the `lakefile.lean` searchPathRef.set compile_time_search_path% + -- It may be reasonable to remove this again after https://github.com/leanprover/lean4/pull/6325 + unsafe enableInitializersExecution unsafe withImportModules #[{module := to}] {} (trustLevel := 1024) fun env => do let graph := env.importGraph let sha ← headSha diff --git a/LongestPole/SpeedCenterJson.lean b/LongestPole/SpeedCenterJson.lean index 20a39f872dd0c..007d464cc463a 100644 --- a/LongestPole/SpeedCenterJson.lean +++ b/LongestPole/SpeedCenterJson.lean @@ -7,7 +7,7 @@ import Lean.Data.Json open Lean /-! -# `structure`s for the http://speed.lean-fro.org/ API +# `structure`s for the https://speed.lean-lang.org/ API -/ namespace SpeedCenterAPI @@ -42,7 +42,7 @@ structure Run where result : Result deriving ToJson, FromJson -/-- The top-level API response for `http://speed.lean-fro.org/{repo}/api/run/{guid}?hash={sha}`. -/ +/-- The top-level API response for `https://speed.lean-lang.org/{repo}/api/run/{guid}?hash={sha}`. -/ structure RunResponse where run : Run deriving ToJson, FromJson diff --git a/LongestPole/Unused.lean b/LongestPole/Unused.lean index ebf4d74987ec3..5e405339d7b4b 100644 --- a/LongestPole/Unused.lean +++ b/LongestPole/Unused.lean @@ -63,6 +63,8 @@ def unusedImportsCLI (args : Cli.Parsed) : IO UInt32 := do -- The code below assumes that it is "deeper files first", as reported by `lake exe pole`. searchPathRef.set compile_time_search_path% + -- It may be reasonable to remove this again after https://github.com/leanprover/lean4/pull/6325 + unsafe enableInitializersExecution let (unused, _) ← unsafe withImportModules #[{module := `Mathlib}] {} (trustLevel := 1024) fun env => Prod.fst <$> Core.CoreM.toIO (ctx := { fileName := "", fileMap := default }) (s := { env := env }) do diff --git a/Mathlib.lean b/Mathlib.lean index e120a6f2afe6e..ea1bb97380bd1 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -153,6 +153,7 @@ import Mathlib.Algebra.Category.Ring.Instances import Mathlib.Algebra.Category.Ring.Limits import Mathlib.Algebra.Category.Ring.LinearAlgebra import Mathlib.Algebra.Category.Ring.Under.Basic +import Mathlib.Algebra.Category.Ring.Under.Limits import Mathlib.Algebra.Category.Semigrp.Basic import Mathlib.Algebra.Central.Basic import Mathlib.Algebra.Central.Defs @@ -201,6 +202,7 @@ import Mathlib.Algebra.DirectSum.LinearMap import Mathlib.Algebra.DirectSum.Module import Mathlib.Algebra.DirectSum.Ring import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Divisibility.Hom import Mathlib.Algebra.Divisibility.Prod import Mathlib.Algebra.Divisibility.Units import Mathlib.Algebra.DualNumber @@ -319,6 +321,7 @@ import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Group.Subgroup.ZPowers.Basic import Mathlib.Algebra.Group.Subgroup.ZPowers.Lemmas import Mathlib.Algebra.Group.Submonoid.Basic +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Group.Submonoid.Defs import Mathlib.Algebra.Group.Submonoid.DistribMulAction import Mathlib.Algebra.Group.Submonoid.Membership @@ -404,6 +407,7 @@ import Mathlib.Algebra.Homology.DifferentialObject import Mathlib.Algebra.Homology.Embedding.Basic import Mathlib.Algebra.Homology.Embedding.Boundary import Mathlib.Algebra.Homology.Embedding.Extend +import Mathlib.Algebra.Homology.Embedding.ExtendHomology import Mathlib.Algebra.Homology.Embedding.HomEquiv import Mathlib.Algebra.Homology.Embedding.IsSupported import Mathlib.Algebra.Homology.Embedding.Restriction @@ -550,6 +554,7 @@ import Mathlib.Algebra.Module.Presentation.Differentials import Mathlib.Algebra.Module.Presentation.DirectSum import Mathlib.Algebra.Module.Presentation.Finite import Mathlib.Algebra.Module.Presentation.Free +import Mathlib.Algebra.Module.Presentation.RestrictScalars import Mathlib.Algebra.Module.Presentation.Tautological import Mathlib.Algebra.Module.Prod import Mathlib.Algebra.Module.Projective @@ -933,6 +938,7 @@ import Mathlib.Algebra.Tropical.Basic import Mathlib.Algebra.Tropical.BigOperators import Mathlib.Algebra.Tropical.Lattice import Mathlib.Algebra.Vertex.HVertexOperator +import Mathlib.Algebra.Vertex.VertexOperator import Mathlib.AlgebraicGeometry.AffineScheme import Mathlib.AlgebraicGeometry.AffineSpace import Mathlib.AlgebraicGeometry.Cover.MorphismProperty @@ -942,8 +948,9 @@ import Mathlib.AlgebraicGeometry.EllipticCurve.Affine import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Basic import Mathlib.AlgebraicGeometry.EllipticCurve.DivisionPolynomial.Degree import Mathlib.AlgebraicGeometry.EllipticCurve.Group -import Mathlib.AlgebraicGeometry.EllipticCurve.J +import Mathlib.AlgebraicGeometry.EllipticCurve.IsomOfJ import Mathlib.AlgebraicGeometry.EllipticCurve.Jacobian +import Mathlib.AlgebraicGeometry.EllipticCurve.ModelsWithJ import Mathlib.AlgebraicGeometry.EllipticCurve.NormalForms import Mathlib.AlgebraicGeometry.EllipticCurve.Projective import Mathlib.AlgebraicGeometry.EllipticCurve.VariableChange @@ -1005,6 +1012,7 @@ import Mathlib.AlgebraicGeometry.Scheme import Mathlib.AlgebraicGeometry.Sites.BigZariski import Mathlib.AlgebraicGeometry.Sites.Etale import Mathlib.AlgebraicGeometry.Sites.MorphismProperty +import Mathlib.AlgebraicGeometry.Sites.Small import Mathlib.AlgebraicGeometry.Spec import Mathlib.AlgebraicGeometry.SpreadingOut import Mathlib.AlgebraicGeometry.Stalk @@ -1048,6 +1056,7 @@ import Mathlib.AlgebraicTopology.SimplicialCategory.SimplicialObject import Mathlib.AlgebraicTopology.SimplicialObject.Basic import Mathlib.AlgebraicTopology.SimplicialObject.Coskeletal import Mathlib.AlgebraicTopology.SimplicialSet.Basic +import Mathlib.AlgebraicTopology.SimplicialSet.Coskeletal import Mathlib.AlgebraicTopology.SimplicialSet.KanComplex import Mathlib.AlgebraicTopology.SimplicialSet.Monoidal import Mathlib.AlgebraicTopology.SimplicialSet.Nerve @@ -1063,6 +1072,7 @@ import Mathlib.Analysis.Analytic.Composition import Mathlib.Analysis.Analytic.Constructions import Mathlib.Analysis.Analytic.Inverse import Mathlib.Analysis.Analytic.IsolatedZeros +import Mathlib.Analysis.Analytic.IteratedFDeriv import Mathlib.Analysis.Analytic.Linear import Mathlib.Analysis.Analytic.Meromorphic import Mathlib.Analysis.Analytic.OfScalars @@ -1126,7 +1136,6 @@ import Mathlib.Analysis.Calculus.BumpFunction.InnerProduct import Mathlib.Analysis.Calculus.BumpFunction.Normed import Mathlib.Analysis.Calculus.Conformal.InnerProduct import Mathlib.Analysis.Calculus.Conformal.NormedSpace -import Mathlib.Analysis.Calculus.ContDiff.Analytic import Mathlib.Analysis.Calculus.ContDiff.Basic import Mathlib.Analysis.Calculus.ContDiff.Bounds import Mathlib.Analysis.Calculus.ContDiff.CPolynomial @@ -1621,6 +1630,7 @@ import Mathlib.CategoryTheory.Category.Basic import Mathlib.CategoryTheory.Category.Bipointed import Mathlib.CategoryTheory.Category.Cat import Mathlib.CategoryTheory.Category.Cat.Adjunction +import Mathlib.CategoryTheory.Category.Cat.AsSmall import Mathlib.CategoryTheory.Category.Cat.Limit import Mathlib.CategoryTheory.Category.Factorisation import Mathlib.CategoryTheory.Category.GaloisConnection @@ -2000,6 +2010,7 @@ import Mathlib.CategoryTheory.MorphismProperty.IsInvertedBy import Mathlib.CategoryTheory.MorphismProperty.Limits import Mathlib.CategoryTheory.MorphismProperty.OverAdjunction import Mathlib.CategoryTheory.MorphismProperty.Representable +import Mathlib.CategoryTheory.MorphismProperty.Retract import Mathlib.CategoryTheory.NatIso import Mathlib.CategoryTheory.NatTrans import Mathlib.CategoryTheory.Noetherian @@ -2038,6 +2049,7 @@ import Mathlib.CategoryTheory.Products.Unitor import Mathlib.CategoryTheory.Quotient import Mathlib.CategoryTheory.Quotient.Linear import Mathlib.CategoryTheory.Quotient.Preadditive +import Mathlib.CategoryTheory.Retract import Mathlib.CategoryTheory.Shift.Basic import Mathlib.CategoryTheory.Shift.CommShift import Mathlib.CategoryTheory.Shift.Induced @@ -2125,7 +2137,10 @@ import Mathlib.CategoryTheory.Sites.Whiskering import Mathlib.CategoryTheory.Skeletal import Mathlib.CategoryTheory.SmallObject.Construction import Mathlib.CategoryTheory.SmallObject.Iteration.Basic +import Mathlib.CategoryTheory.SmallObject.Iteration.ExtendToSucc +import Mathlib.CategoryTheory.SmallObject.Iteration.Nonempty import Mathlib.CategoryTheory.SmallObject.Iteration.UniqueHom +import Mathlib.CategoryTheory.SmallObject.WellOrderInductionData import Mathlib.CategoryTheory.Square import Mathlib.CategoryTheory.Subobject.Basic import Mathlib.CategoryTheory.Subobject.Comma @@ -2161,6 +2176,7 @@ import Mathlib.Combinatorics.Additive.AP.Three.Defs import Mathlib.Combinatorics.Additive.CauchyDavenport import Mathlib.Combinatorics.Additive.Corner.Defs import Mathlib.Combinatorics.Additive.Corner.Roth +import Mathlib.Combinatorics.Additive.CovBySMul import Mathlib.Combinatorics.Additive.Dissociation import Mathlib.Combinatorics.Additive.DoublingConst import Mathlib.Combinatorics.Additive.ETransform @@ -2171,6 +2187,7 @@ import Mathlib.Combinatorics.Additive.PluenneckeRuzsa import Mathlib.Combinatorics.Additive.Randomisation import Mathlib.Combinatorics.Additive.RuzsaCovering import Mathlib.Combinatorics.Additive.SmallTripling +import Mathlib.Combinatorics.Additive.VerySmallDoubling import Mathlib.Combinatorics.Colex import Mathlib.Combinatorics.Configuration import Mathlib.Combinatorics.Derangements.Basic @@ -2186,6 +2203,7 @@ import Mathlib.Combinatorics.Enumerative.DyckWord import Mathlib.Combinatorics.Enumerative.IncidenceAlgebra import Mathlib.Combinatorics.Enumerative.InclusionExclusion import Mathlib.Combinatorics.Enumerative.Partition +import Mathlib.Combinatorics.Extremal.RuzsaSzemeredi import Mathlib.Combinatorics.HalesJewett import Mathlib.Combinatorics.Hall.Basic import Mathlib.Combinatorics.Hall.Finite @@ -2384,6 +2402,7 @@ import Mathlib.Data.ENNReal.Operations import Mathlib.Data.ENNReal.Real import Mathlib.Data.ENat.Basic import Mathlib.Data.ENat.BigOperators +import Mathlib.Data.ENat.Defs import Mathlib.Data.ENat.Lattice import Mathlib.Data.Erased import Mathlib.Data.FP.Basic @@ -2474,12 +2493,14 @@ import Mathlib.Data.Finsupp.Indicator import Mathlib.Data.Finsupp.Interval import Mathlib.Data.Finsupp.Lex import Mathlib.Data.Finsupp.MonomialOrder +import Mathlib.Data.Finsupp.MonomialOrder.DegLex import Mathlib.Data.Finsupp.Multiset import Mathlib.Data.Finsupp.NeLocus import Mathlib.Data.Finsupp.Notation import Mathlib.Data.Finsupp.Order import Mathlib.Data.Finsupp.PWO import Mathlib.Data.Finsupp.Pointwise +import Mathlib.Data.Finsupp.SMulWithZero import Mathlib.Data.Finsupp.ToDFinsupp import Mathlib.Data.Finsupp.Weight import Mathlib.Data.Finsupp.WellFounded @@ -2518,6 +2539,7 @@ import Mathlib.Data.Int.Cast.Basic import Mathlib.Data.Int.Cast.Defs import Mathlib.Data.Int.Cast.Field import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Data.Int.Cast.Pi import Mathlib.Data.Int.Cast.Prod import Mathlib.Data.Int.CharZero import Mathlib.Data.Int.ConditionallyCompleteOrder @@ -2762,6 +2784,7 @@ import Mathlib.Data.PNat.Equiv import Mathlib.Data.PNat.Factors import Mathlib.Data.PNat.Find import Mathlib.Data.PNat.Interval +import Mathlib.Data.PNat.Notation import Mathlib.Data.PNat.Prime import Mathlib.Data.PNat.Xgcd import Mathlib.Data.PSigma.Order @@ -2916,6 +2939,9 @@ import Mathlib.Data.ZMod.Units import Mathlib.Deprecated.AlgebraClasses import Mathlib.Deprecated.Aliases import Mathlib.Deprecated.ByteArray +import Mathlib.Deprecated.Cardinal.Continuum +import Mathlib.Deprecated.Cardinal.Finite +import Mathlib.Deprecated.Cardinal.PartENat import Mathlib.Deprecated.Combinator import Mathlib.Deprecated.Equiv import Mathlib.Deprecated.Group @@ -3079,6 +3105,7 @@ import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners import Mathlib.Geometry.Manifold.VectorBundle.Basic import Mathlib.Geometry.Manifold.VectorBundle.FiberwiseLinear import Mathlib.Geometry.Manifold.VectorBundle.Hom +import Mathlib.Geometry.Manifold.VectorBundle.MDifferentiable import Mathlib.Geometry.Manifold.VectorBundle.Pullback import Mathlib.Geometry.Manifold.VectorBundle.SmoothSection import Mathlib.Geometry.Manifold.VectorBundle.Tangent @@ -3297,6 +3324,7 @@ import Mathlib.LinearAlgebra.Determinant import Mathlib.LinearAlgebra.Dimension.Basic import Mathlib.LinearAlgebra.Dimension.Constructions import Mathlib.LinearAlgebra.Dimension.DivisionRing +import Mathlib.LinearAlgebra.Dimension.ErdosKaplansky import Mathlib.LinearAlgebra.Dimension.Finite import Mathlib.LinearAlgebra.Dimension.Finrank import Mathlib.LinearAlgebra.Dimension.Free @@ -3305,7 +3333,8 @@ import Mathlib.LinearAlgebra.Dimension.LinearMap import Mathlib.LinearAlgebra.Dimension.Localization import Mathlib.LinearAlgebra.Dimension.RankNullity import Mathlib.LinearAlgebra.Dimension.StrongRankCondition -import Mathlib.LinearAlgebra.Dimension.Torsion +import Mathlib.LinearAlgebra.Dimension.Torsion.Basic +import Mathlib.LinearAlgebra.Dimension.Torsion.Finite import Mathlib.LinearAlgebra.DirectSum.Finsupp import Mathlib.LinearAlgebra.DirectSum.TensorProduct import Mathlib.LinearAlgebra.Dual @@ -3319,6 +3348,7 @@ import Mathlib.LinearAlgebra.Eigenspace.Zero import Mathlib.LinearAlgebra.ExteriorAlgebra.Basic import Mathlib.LinearAlgebra.ExteriorAlgebra.Grading import Mathlib.LinearAlgebra.ExteriorAlgebra.OfAlternating +import Mathlib.LinearAlgebra.ExteriorPower.Basic import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.LinearAlgebra.FiniteDimensional.Defs import Mathlib.LinearAlgebra.FiniteSpan @@ -3342,6 +3372,7 @@ import Mathlib.LinearAlgebra.FreeModule.PID import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition import Mathlib.LinearAlgebra.FreeProduct.Basic import Mathlib.LinearAlgebra.GeneralLinearGroup +import Mathlib.LinearAlgebra.Goursat import Mathlib.LinearAlgebra.InvariantBasisNumber import Mathlib.LinearAlgebra.Isomorphisms import Mathlib.LinearAlgebra.JordanChevalley @@ -3392,6 +3423,7 @@ import Mathlib.LinearAlgebra.Matrix.PosDef import Mathlib.LinearAlgebra.Matrix.ProjectiveSpecialLinearGroup import Mathlib.LinearAlgebra.Matrix.Reindex import Mathlib.LinearAlgebra.Matrix.SchurComplement +import Mathlib.LinearAlgebra.Matrix.SemiringInverse import Mathlib.LinearAlgebra.Matrix.SesquilinearForm import Mathlib.LinearAlgebra.Matrix.SpecialLinearGroup import Mathlib.LinearAlgebra.Matrix.Spectrum @@ -3445,6 +3477,7 @@ import Mathlib.LinearAlgebra.RootSystem.Hom import Mathlib.LinearAlgebra.RootSystem.OfBilinear import Mathlib.LinearAlgebra.RootSystem.RootPairingCat import Mathlib.LinearAlgebra.RootSystem.RootPositive +import Mathlib.LinearAlgebra.RootSystem.WeylGroup import Mathlib.LinearAlgebra.SModEq import Mathlib.LinearAlgebra.Semisimple import Mathlib.LinearAlgebra.SesquilinearForm @@ -3753,6 +3786,7 @@ import Mathlib.ModelTheory.Syntax import Mathlib.ModelTheory.Types import Mathlib.ModelTheory.Ultraproducts import Mathlib.NumberTheory.ADEInequality +import Mathlib.NumberTheory.AbelSummation import Mathlib.NumberTheory.ArithmeticFunction import Mathlib.NumberTheory.Basic import Mathlib.NumberTheory.Bernoulli @@ -3862,6 +3896,7 @@ import Mathlib.NumberTheory.NumberField.Discriminant.Basic import Mathlib.NumberTheory.NumberField.Discriminant.Defs import Mathlib.NumberTheory.NumberField.Embeddings import Mathlib.NumberTheory.NumberField.EquivReindex +import Mathlib.NumberTheory.NumberField.FinitePlaces import Mathlib.NumberTheory.NumberField.FractionalIdeal import Mathlib.NumberTheory.NumberField.House import Mathlib.NumberTheory.NumberField.Norm @@ -3974,6 +4009,7 @@ import Mathlib.Order.Extension.Well import Mathlib.Order.Filter.AtTopBot import Mathlib.Order.Filter.AtTopBot.Archimedean import Mathlib.Order.Filter.AtTopBot.BigOperators +import Mathlib.Order.Filter.AtTopBot.CountablyGenerated import Mathlib.Order.Filter.AtTopBot.Field import Mathlib.Order.Filter.AtTopBot.Floor import Mathlib.Order.Filter.AtTopBot.Group @@ -3987,6 +4023,7 @@ import Mathlib.Order.Filter.Cocardinal import Mathlib.Order.Filter.Cofinite import Mathlib.Order.Filter.CountableInter import Mathlib.Order.Filter.CountableSeparatingOn +import Mathlib.Order.Filter.CountablyGenerated import Mathlib.Order.Filter.Curry import Mathlib.Order.Filter.Defs import Mathlib.Order.Filter.ENNReal @@ -4100,6 +4137,7 @@ import Mathlib.Order.Sublattice import Mathlib.Order.SuccPred.Archimedean import Mathlib.Order.SuccPred.Basic import Mathlib.Order.SuccPred.CompleteLinearOrder +import Mathlib.Order.SuccPred.InitialSeg import Mathlib.Order.SuccPred.IntervalSucc import Mathlib.Order.SuccPred.Limit import Mathlib.Order.SuccPred.LinearLocallyFinite @@ -4139,7 +4177,10 @@ import Mathlib.Probability.Independence.Kernel import Mathlib.Probability.Independence.ZeroOne import Mathlib.Probability.Integration import Mathlib.Probability.Kernel.Basic -import Mathlib.Probability.Kernel.Composition +import Mathlib.Probability.Kernel.Composition.Basic +import Mathlib.Probability.Kernel.Composition.IntegralCompProd +import Mathlib.Probability.Kernel.Composition.MeasureCompProd +import Mathlib.Probability.Kernel.Composition.ParallelComp import Mathlib.Probability.Kernel.CondDistrib import Mathlib.Probability.Kernel.Condexp import Mathlib.Probability.Kernel.Defs @@ -4152,10 +4193,8 @@ import Mathlib.Probability.Kernel.Disintegration.MeasurableStieltjes import Mathlib.Probability.Kernel.Disintegration.StandardBorel import Mathlib.Probability.Kernel.Disintegration.Unique import Mathlib.Probability.Kernel.Integral -import Mathlib.Probability.Kernel.IntegralCompProd import Mathlib.Probability.Kernel.Invariance import Mathlib.Probability.Kernel.MeasurableIntegral -import Mathlib.Probability.Kernel.MeasureCompProd import Mathlib.Probability.Kernel.RadonNikodym import Mathlib.Probability.Kernel.WithDensity import Mathlib.Probability.Martingale.Basic @@ -4204,13 +4243,24 @@ import Mathlib.RingTheory.Adjoin.Basic import Mathlib.RingTheory.Adjoin.Dimension import Mathlib.RingTheory.Adjoin.FG import Mathlib.RingTheory.Adjoin.Field +import Mathlib.RingTheory.Adjoin.Polynomial import Mathlib.RingTheory.Adjoin.PowerBasis import Mathlib.RingTheory.Adjoin.Tower import Mathlib.RingTheory.AdjoinRoot import Mathlib.RingTheory.AlgebraTower -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Basic import Mathlib.RingTheory.Algebraic.Cardinality -import Mathlib.RingTheory.AlgebraicIndependent +import Mathlib.RingTheory.Algebraic.Defs +import Mathlib.RingTheory.Algebraic.Integral +import Mathlib.RingTheory.Algebraic.LinearIndependent +import Mathlib.RingTheory.Algebraic.MvPolynomial +import Mathlib.RingTheory.Algebraic.Pi +import Mathlib.RingTheory.AlgebraicIndependent.Adjoin +import Mathlib.RingTheory.AlgebraicIndependent.Basic +import Mathlib.RingTheory.AlgebraicIndependent.Defs +import Mathlib.RingTheory.AlgebraicIndependent.RankAndCardinality +import Mathlib.RingTheory.AlgebraicIndependent.TranscendenceBasis +import Mathlib.RingTheory.AlgebraicIndependent.Transcendental import Mathlib.RingTheory.Artinian import Mathlib.RingTheory.Bezout import Mathlib.RingTheory.Bialgebra.Basic @@ -4278,7 +4328,6 @@ import Mathlib.RingTheory.Finiteness.Projective import Mathlib.RingTheory.Finiteness.Subalgebra import Mathlib.RingTheory.Finiteness.TensorProduct import Mathlib.RingTheory.Fintype -import Mathlib.RingTheory.Flat.Algebra import Mathlib.RingTheory.Flat.Basic import Mathlib.RingTheory.Flat.CategoryTheory import Mathlib.RingTheory.Flat.Equalizer @@ -4349,8 +4398,9 @@ import Mathlib.RingTheory.IntegralDomain import Mathlib.RingTheory.IsAdjoinRoot import Mathlib.RingTheory.IsPrimary import Mathlib.RingTheory.IsTensorProduct -import Mathlib.RingTheory.Jacobson -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Ideal +import Mathlib.RingTheory.Jacobson.Polynomial +import Mathlib.RingTheory.Jacobson.Ring import Mathlib.RingTheory.Kaehler.Basic import Mathlib.RingTheory.Kaehler.CotangentComplex import Mathlib.RingTheory.Kaehler.Polynomial @@ -4404,10 +4454,13 @@ import Mathlib.RingTheory.MaximalSpectrum import Mathlib.RingTheory.Multiplicity import Mathlib.RingTheory.MvPolynomial import Mathlib.RingTheory.MvPolynomial.Basic +import Mathlib.RingTheory.MvPolynomial.EulerIdentity import Mathlib.RingTheory.MvPolynomial.FreeCommRing +import Mathlib.RingTheory.MvPolynomial.Groebner import Mathlib.RingTheory.MvPolynomial.Homogeneous import Mathlib.RingTheory.MvPolynomial.Ideal import Mathlib.RingTheory.MvPolynomial.Localization +import Mathlib.RingTheory.MvPolynomial.MonomialOrder import Mathlib.RingTheory.MvPolynomial.Symmetric.Defs import Mathlib.RingTheory.MvPolynomial.Symmetric.FundamentalTheorem import Mathlib.RingTheory.MvPolynomial.Symmetric.NewtonIdentities @@ -4418,6 +4471,7 @@ import Mathlib.RingTheory.MvPowerSeries.Inverse import Mathlib.RingTheory.MvPowerSeries.LexOrder import Mathlib.RingTheory.MvPowerSeries.NoZeroDivisors import Mathlib.RingTheory.MvPowerSeries.Order +import Mathlib.RingTheory.MvPowerSeries.PiTopology import Mathlib.RingTheory.MvPowerSeries.Trunc import Mathlib.RingTheory.Nakayama import Mathlib.RingTheory.Nilpotent.Basic @@ -4458,6 +4512,8 @@ import Mathlib.RingTheory.Polynomial.Eisenstein.IsIntegral import Mathlib.RingTheory.Polynomial.GaussLemma import Mathlib.RingTheory.Polynomial.Hermite.Basic import Mathlib.RingTheory.Polynomial.Hermite.Gaussian +import Mathlib.RingTheory.Polynomial.HilbertPoly +import Mathlib.RingTheory.Polynomial.Ideal import Mathlib.RingTheory.Polynomial.IntegralNormalization import Mathlib.RingTheory.Polynomial.IrreducibleRing import Mathlib.RingTheory.Polynomial.Nilpotent @@ -4479,6 +4535,7 @@ import Mathlib.RingTheory.PowerSeries.Basic import Mathlib.RingTheory.PowerSeries.Derivative import Mathlib.RingTheory.PowerSeries.Inverse import Mathlib.RingTheory.PowerSeries.Order +import Mathlib.RingTheory.PowerSeries.PiTopology import Mathlib.RingTheory.PowerSeries.Trunc import Mathlib.RingTheory.PowerSeries.WellKnown import Mathlib.RingTheory.Presentation @@ -4494,6 +4551,7 @@ import Mathlib.RingTheory.Regular.RegularSequence import Mathlib.RingTheory.RingHom.Finite import Mathlib.RingTheory.RingHom.FinitePresentation import Mathlib.RingTheory.RingHom.FiniteType +import Mathlib.RingTheory.RingHom.Flat import Mathlib.RingTheory.RingHom.Injective import Mathlib.RingTheory.RingHom.Integral import Mathlib.RingTheory.RingHom.Locally @@ -4523,6 +4581,8 @@ import Mathlib.RingTheory.TensorProduct.Basic import Mathlib.RingTheory.TensorProduct.Finite import Mathlib.RingTheory.TensorProduct.Free import Mathlib.RingTheory.TensorProduct.MvPolynomial +import Mathlib.RingTheory.TensorProduct.Nontrivial +import Mathlib.RingTheory.TensorProduct.Pi import Mathlib.RingTheory.Trace.Basic import Mathlib.RingTheory.Trace.Defs import Mathlib.RingTheory.Trace.Quotient @@ -4591,7 +4651,6 @@ import Mathlib.SetTheory.Cardinal.ENat import Mathlib.SetTheory.Cardinal.Finite import Mathlib.SetTheory.Cardinal.Finsupp import Mathlib.SetTheory.Cardinal.Free -import Mathlib.SetTheory.Cardinal.PartENat import Mathlib.SetTheory.Cardinal.SchroederBernstein import Mathlib.SetTheory.Cardinal.Subfield import Mathlib.SetTheory.Cardinal.ToNat @@ -4916,6 +4975,7 @@ import Mathlib.Topology.Algebra.Group.SubmonoidClosure import Mathlib.Topology.Algebra.Group.TopologicalAbelianization import Mathlib.Topology.Algebra.GroupCompletion import Mathlib.Topology.Algebra.GroupWithZero +import Mathlib.Topology.Algebra.Indicator import Mathlib.Topology.Algebra.InfiniteSum.Basic import Mathlib.Topology.Algebra.InfiniteSum.Constructions import Mathlib.Topology.Algebra.InfiniteSum.Defs @@ -4978,6 +5038,7 @@ import Mathlib.Topology.Algebra.SeparationQuotient.Basic import Mathlib.Topology.Algebra.SeparationQuotient.Section import Mathlib.Topology.Algebra.Star import Mathlib.Topology.Algebra.StarSubalgebra +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.Algebra.UniformConvergence import Mathlib.Topology.Algebra.UniformField import Mathlib.Topology.Algebra.UniformFilterBasis @@ -5111,6 +5172,7 @@ import Mathlib.Topology.DerivedSet import Mathlib.Topology.DiscreteQuotient import Mathlib.Topology.DiscreteSubset import Mathlib.Topology.EMetricSpace.Basic +import Mathlib.Topology.EMetricSpace.BoundedVariation import Mathlib.Topology.EMetricSpace.Defs import Mathlib.Topology.EMetricSpace.Diam import Mathlib.Topology.EMetricSpace.Lipschitz @@ -5310,7 +5372,6 @@ import Mathlib.Topology.Sober import Mathlib.Topology.Specialization import Mathlib.Topology.Spectral.Hom import Mathlib.Topology.StoneCech -import Mathlib.Topology.Support import Mathlib.Topology.TietzeExtension import Mathlib.Topology.Ultrafilter import Mathlib.Topology.UniformSpace.AbsoluteValue @@ -5323,6 +5384,7 @@ import Mathlib.Topology.UniformSpace.CompactConvergence import Mathlib.Topology.UniformSpace.CompareReals import Mathlib.Topology.UniformSpace.CompleteSeparated import Mathlib.Topology.UniformSpace.Completion +import Mathlib.Topology.UniformSpace.Dini import Mathlib.Topology.UniformSpace.Equicontinuity import Mathlib.Topology.UniformSpace.Equiv import Mathlib.Topology.UniformSpace.HeineCantor @@ -5352,7 +5414,6 @@ import Mathlib.Util.DischargerAsTactic import Mathlib.Util.Export import Mathlib.Util.FormatTable import Mathlib.Util.GetAllModules -import Mathlib.Util.IncludeStr import Mathlib.Util.LongNames import Mathlib.Util.MemoFix import Mathlib.Util.Notation3 @@ -5363,5 +5424,6 @@ import Mathlib.Util.Superscript import Mathlib.Util.SynthesizeUsing import Mathlib.Util.Tactic import Mathlib.Util.TermBeta +import Mathlib.Util.TransImports import Mathlib.Util.WhatsNew import Mathlib.Util.WithWeakNamespace diff --git a/Mathlib/Algebra/AddTorsor.lean b/Mathlib/Algebra/AddTorsor.lean index 5c7a2b005055b..c853185785a74 100644 --- a/Mathlib/Algebra/AddTorsor.lean +++ b/Mathlib/Algebra/AddTorsor.lean @@ -49,7 +49,7 @@ class AddTorsor (G : outParam Type*) (P : Type*) [AddGroup G] extends AddAction /-- Torsor subtraction and addition with the same element cancels out. -/ vsub_vadd' : ∀ p₁ p₂ : P, (p₁ -ᵥ p₂ : G) +ᵥ p₂ = p₁ /-- Torsor addition and subtraction with the same element cancels out. -/ - vadd_vsub' : ∀ (g : G) (p : P), g +ᵥ p -ᵥ p = g + vadd_vsub' : ∀ (g : G) (p : P), (g +ᵥ p) -ᵥ p = g -- Porting note (https://github.com/leanprover-community/mathlib4/issues/12096): removed `nolint instance_priority`; lint not ported yet attribute [instance 100] AddTorsor.nonempty @@ -75,19 +75,18 @@ variable {G : Type*} {P : Type*} [AddGroup G] [T : AddTorsor G P] /-- Adding the result of subtracting from another point produces that point. -/ @[simp] -theorem vsub_vadd (p₁ p₂ : P) : p₁ -ᵥ p₂ +ᵥ p₂ = p₁ := +theorem vsub_vadd (p₁ p₂ : P) : (p₁ -ᵥ p₂) +ᵥ p₂ = p₁ := AddTorsor.vsub_vadd' p₁ p₂ /-- Adding a group element then subtracting the original point produces that group element. -/ @[simp] -theorem vadd_vsub (g : G) (p : P) : g +ᵥ p -ᵥ p = g := +theorem vadd_vsub (g : G) (p : P) : (g +ᵥ p) -ᵥ p = g := AddTorsor.vadd_vsub' g p /-- If the same point added to two group elements produces equal results, those group elements are equal. -/ theorem vadd_right_cancel {g₁ g₂ : G} (p : P) (h : g₁ +ᵥ p = g₂ +ᵥ p) : g₁ = g₂ := by --- Porting note: vadd_vsub g₁ → vadd_vsub g₁ p rw [← vadd_vsub g₁ p, h, vadd_vsub] @[simp] @@ -102,7 +101,7 @@ theorem vadd_right_injective (p : P) : Function.Injective ((· +ᵥ p) : G → P /-- Adding a group element to a point, then subtracting another point, produces the same result as subtracting the points then adding the group element. -/ -theorem vadd_vsub_assoc (g : G) (p₁ p₂ : P) : g +ᵥ p₁ -ᵥ p₂ = g + (p₁ -ᵥ p₂) := by +theorem vadd_vsub_assoc (g : G) (p₁ p₂ : P) : (g +ᵥ p₁) -ᵥ p₂ = g + (p₁ -ᵥ p₂) := by apply vadd_right_cancel p₂ rw [vsub_vadd, add_vadd, vsub_vadd] @@ -137,7 +136,7 @@ theorem neg_vsub_eq_vsub_rev (p₁ p₂ : P) : -(p₁ -ᵥ p₂) = p₂ -ᵥ p refine neg_eq_of_add_eq_zero_right (vadd_right_cancel p₁ ?_) rw [vsub_add_vsub_cancel, vsub_self] -theorem vadd_vsub_eq_sub_vsub (g : G) (p q : P) : g +ᵥ p -ᵥ q = g - (q -ᵥ p) := by +theorem vadd_vsub_eq_sub_vsub (g : G) (p q : P) : (g +ᵥ p) -ᵥ q = g - (q -ᵥ p) := by rw [vadd_vsub_assoc, sub_eq_add_neg, neg_vsub_eq_vsub_rev] /-- Subtracting the result of adding a group element produces the same result @@ -171,7 +170,7 @@ theorem singleton_vsub_self (p : P) : ({p} : Set P) -ᵥ {p} = {(0 : G)} := by end Set @[simp] -theorem vadd_vsub_vadd_cancel_right (v₁ v₂ : G) (p : P) : v₁ +ᵥ p -ᵥ (v₂ +ᵥ p) = v₁ - v₂ := by +theorem vadd_vsub_vadd_cancel_right (v₁ v₂ : G) (p : P) : (v₁ +ᵥ p) -ᵥ (v₂ +ᵥ p) = v₁ - v₂ := by rw [vsub_vadd_eq_vsub_sub, vadd_vsub_assoc, vsub_self, add_zero] /-- If the same point subtracted from two points produces equal @@ -218,10 +217,10 @@ theorem vsub_sub_vsub_cancel_left (p₁ p₂ p₃ : P) : p₃ -ᵥ p₂ - (p₃ rw [sub_eq_add_neg, neg_vsub_eq_vsub_rev, add_comm, vsub_add_vsub_cancel] @[simp] -theorem vadd_vsub_vadd_cancel_left (v : G) (p₁ p₂ : P) : v +ᵥ p₁ -ᵥ (v +ᵥ p₂) = p₁ -ᵥ p₂ := by +theorem vadd_vsub_vadd_cancel_left (v : G) (p₁ p₂ : P) : (v +ᵥ p₁) -ᵥ (v +ᵥ p₂) = p₁ -ᵥ p₂ := by rw [vsub_vadd_eq_vsub_sub, vadd_vsub_assoc, add_sub_cancel_left] -theorem vsub_vadd_comm (p₁ p₂ p₃ : P) : (p₁ -ᵥ p₂ : G) +ᵥ p₃ = p₃ -ᵥ p₂ +ᵥ p₁ := by +theorem vsub_vadd_comm (p₁ p₂ p₃ : P) : (p₁ -ᵥ p₂ : G) +ᵥ p₃ = (p₃ -ᵥ p₂) +ᵥ p₁ := by rw [← @vsub_eq_zero_iff_eq G, vadd_vsub_assoc, vsub_vadd_eq_vsub_sub] simp @@ -364,15 +363,13 @@ def constVAddHom : Multiplicative G →* Equiv.Perm P where variable {P} --- Porting note: Previous code was: --- open _Root_.Function open Function /-- Point reflection in `x` as a permutation. -/ def pointReflection (x : P) : Perm P := (constVSub x).trans (vaddConst x) -theorem pointReflection_apply (x y : P) : pointReflection x y = x -ᵥ y +ᵥ x := +theorem pointReflection_apply (x y : P) : pointReflection x y = (x -ᵥ y) +ᵥ x := rfl @[simp] @@ -412,7 +409,6 @@ theorem pointReflection_fixed_iff_of_injective_two_nsmul {x y : P} (h : Injectiv @[deprecated (since := "2024-11-18")] alias pointReflection_fixed_iff_of_injective_bit0 := pointReflection_fixed_iff_of_injective_two_nsmul --- Porting note: need this to calm down CI theorem injective_pointReflection_left_of_injective_two_nsmul {G P : Type*} [AddCommGroup G] [AddTorsor G P] (h : Injective (2 • · : G → G)) (y : P) : Injective fun x : P => pointReflection x y := diff --git a/Mathlib/Algebra/Algebra/Bilinear.lean b/Mathlib/Algebra/Algebra/Bilinear.lean index 02c54d00368ef..2abf893a86632 100644 --- a/Mathlib/Algebra/Algebra/Bilinear.lean +++ b/Mathlib/Algebra/Algebra/Bilinear.lean @@ -21,13 +21,71 @@ open TensorProduct Module namespace LinearMap section NonUnitalNonAssoc +variable (R A : Type*) -variable (R A : Type*) [CommSemiring R] [NonUnitalNonAssocSemiring A] [Module R A] - [SMulCommClass R A A] [IsScalarTower R A A] +section one_side +variable [Semiring R] [NonUnitalNonAssocSemiring A] [Module R A] + +section left +variable {A} [SMulCommClass R A A] + +/-- The multiplication on the left in a algebra is a linear map. + +Note that this only assumes `SMulCommClass R A A`, so that it also works for `R := Aᵐᵒᵖ`. + +When `A` is unital and associative, this is the same as `DistribMulAction.toLinearMap R A a` -/ +def mulLeft (a : A) : A →ₗ[R] A where + toFun := (a * ·) + map_add' := mul_add _ + map_smul' _ := mul_smul_comm _ _ + +@[simp] +theorem mulLeft_apply (a b : A) : mulLeft R a b = a * b := rfl + +@[simp] +theorem mulLeft_toAddMonoidHom (a : A) : (mulLeft R a : A →+ A) = AddMonoidHom.mulLeft a := rfl + +variable (A) in +@[simp] +theorem mulLeft_zero_eq_zero : mulLeft R (0 : A) = 0 := ext fun _ => zero_mul _ + +end left + +section right +variable {A} [IsScalarTower R A A] + +/-- The multiplication on the right in an algebra is a linear map. + +Note that this only assumes `IsScalarTower R A A`, so that it also works for `R := A`. + +When `A` is unital and associative, this is the same as +`DistribMulAction.toLinearMap R A (MulOpposite.op b)`. -/ +def mulRight (b : A) : A →ₗ[R] A where + toFun := (· * b) + map_add' _ _ := add_mul _ _ _ + map_smul' _ _ := smul_mul_assoc _ _ _ + +@[simp] +theorem mulRight_apply (a b : A) : mulRight R a b = b * a := rfl + +@[simp] +theorem mulRight_toAddMonoidHom (a : A) : (mulRight R a : A →+ A) = AddMonoidHom.mulRight a := rfl + +variable (A) in +@[simp] +theorem mulRight_zero_eq_zero : mulRight R (0 : A) = 0 := ext fun _ => mul_zero _ + +end right + +end one_side + +variable [CommSemiring R] [NonUnitalNonAssocSemiring A] [Module R A] +variable [SMulCommClass R A A] [IsScalarTower R A A] /-- The multiplication in a non-unital non-associative algebra is a bilinear map. A weaker version of this for semirings exists as `AddMonoidHom.mul`. -/ +@[simps!] def mul : A →ₗ[R] A →ₗ[R] A := LinearMap.mk₂ R (· * ·) add_mul smul_mul_assoc mul_add mul_smul_comm @@ -38,40 +96,16 @@ noncomputable def mul' : A ⊗[R] A →ₗ[R] A := variable {A} -/-- The multiplication on the left in a non-unital algebra is a linear map. -/ -def mulLeft (a : A) : A →ₗ[R] A := - mul R A a - -/-- The multiplication on the right in an algebra is a linear map. -/ -def mulRight (a : A) : A →ₗ[R] A := - (mul R A).flip a - /-- Simultaneous multiplication on the left and right is a linear map. -/ def mulLeftRight (ab : A × A) : A →ₗ[R] A := (mulRight R ab.snd).comp (mulLeft R ab.fst) -@[simp] -theorem mulLeft_toAddMonoidHom (a : A) : (mulLeft R a : A →+ A) = AddMonoidHom.mulLeft a := - rfl - -@[simp] -theorem mulRight_toAddMonoidHom (a : A) : (mulRight R a : A →+ A) = AddMonoidHom.mulRight a := - rfl - variable {R} @[simp] theorem mul_apply' (a b : A) : mul R A a b = a * b := rfl -@[simp] -theorem mulLeft_apply (a b : A) : mulLeft R a b = a * b := - rfl - -@[simp] -theorem mulRight_apply (a b : A) : mulRight R a b = b * a := - rfl - @[simp] theorem mulLeftRight_apply (a b x : A) : mulLeftRight R (a, b) x = a * x * b := rfl @@ -80,35 +114,41 @@ theorem mulLeftRight_apply (a b x : A) : mulLeftRight R (a, b) x = a * x * b := theorem mul'_apply {a b : A} : mul' R A (a ⊗ₜ b) = a * b := rfl -@[simp] -theorem mulLeft_zero_eq_zero : mulLeft R (0 : A) = 0 := - (mul R A).map_zero +end NonUnitalNonAssoc + +section NonUnital +variable (R A B : Type*) + +section one_side +variable [Semiring R] [NonUnitalSemiring A] [NonUnitalSemiring B] [Module R B] [Module R A] @[simp] -theorem mulRight_zero_eq_zero : mulRight R (0 : A) = 0 := - (mul R A).flip.map_zero +theorem mulLeft_mul [SMulCommClass R A A] (a b : A) : + mulLeft R (a * b) = (mulLeft R a).comp (mulLeft R b) := by + ext + simp only [mulLeft_apply, comp_apply, mul_assoc] -end NonUnitalNonAssoc +@[simp] +theorem mulRight_mul [IsScalarTower R A A] (a b : A) : + mulRight R (a * b) = (mulRight R b).comp (mulRight R a) := by + ext + simp only [mulRight_apply, comp_apply, mul_assoc] -section NonUnital +end one_side -variable (R A : Type*) [CommSemiring R] [NonUnitalSemiring A] [Module R A] [SMulCommClass R A A] - [IsScalarTower R A A] +variable [CommSemiring R] [NonUnitalSemiring A] [NonUnitalSemiring B] [Module R B] [Module R A] +variable [SMulCommClass R A A] [IsScalarTower R A A] +variable [SMulCommClass R B B] [IsScalarTower R B B] /-- The multiplication in a non-unital algebra is a bilinear map. A weaker version of this for non-unital non-associative algebras exists as `LinearMap.mul`. -/ -def _root_.NonUnitalAlgHom.lmul : A →ₙₐ[R] End R A := - { mul R A with - map_mul' := by - intro a b - ext c - exact mul_assoc a b c - map_zero' := by - ext a - exact zero_mul a } +def _root_.NonUnitalAlgHom.lmul : A →ₙₐ[R] End R A where + __ := mul R A + map_mul' := mulLeft_mul _ _ + map_zero' := mulLeft_zero_eq_zero _ _ -variable {R A} +variable {R A B} @[simp] theorem _root_.NonUnitalAlgHom.coe_lmul_eq_mul : ⇑(NonUnitalAlgHom.lmul R A) = mul R A := @@ -118,23 +158,6 @@ theorem commute_mulLeft_right (a b : A) : Commute (mulLeft R a) (mulRight R b) : ext c exact (mul_assoc a c b).symm -@[simp] -theorem mulLeft_mul (a b : A) : mulLeft R (a * b) = (mulLeft R a).comp (mulLeft R b) := by - ext - simp only [mulLeft_apply, comp_apply, mul_assoc] - -@[simp] -theorem mulRight_mul (a b : A) : mulRight R (a * b) = (mulRight R b).comp (mulRight R a) := by - ext - simp only [mulRight_apply, comp_apply, mul_assoc] - -end NonUnital - -section Semiring - -variable (R A B : Type*) [CommSemiring R] [Semiring A] [Semiring B] [Algebra R A] [Algebra R B] - -variable {R A B} in /-- A `LinearMap` preserves multiplication if pre- and post- composition with `LinearMap.mul` are equivalent. By converting the statement into an equality of `LinearMap`s, this lemma allows various specialized `ext` lemmas about `→ₗ[R]` to then be applied. @@ -145,76 +168,84 @@ theorem map_mul_iff (f : A →ₗ[R] B) : (LinearMap.mul R A).compr₂ f = (LinearMap.mul R B ∘ₗ f).compl₂ f := Iff.symm LinearMap.ext_iff₂ -/-- The multiplication in an algebra is an algebra homomorphism into the endomorphisms on -the algebra. - -A weaker version of this for non-unital algebras exists as `NonUnitalAlgHom.mul`. -/ -def _root_.Algebra.lmul : A →ₐ[R] End R A := - { LinearMap.mul R A with - map_one' := by - ext a - exact one_mul a - map_mul' := by - intro a b - ext c - exact mul_assoc a b c - map_zero' := by - ext a - exact zero_mul a - commutes' := by - intro r - ext a - exact (Algebra.smul_def r a).symm } +end NonUnital -variable {R A} +section Semiring -@[simp] -theorem _root_.Algebra.coe_lmul_eq_mul : ⇑(Algebra.lmul R A) = mul R A := - rfl +variable (R A : Type*) +section one_side +variable [Semiring R] [Semiring A] -theorem _root_.Algebra.lmul_injective : Function.Injective (Algebra.lmul R A) := - fun a₁ a₂ h ↦ by simpa using DFunLike.congr_fun h 1 +section left +variable [Module R A] [SMulCommClass R A A] -theorem _root_.Algebra.lmul_isUnit_iff {x : A} : - IsUnit (Algebra.lmul R A x) ↔ IsUnit x := by - rw [Module.End_isUnit_iff, Iff.comm] - exact IsUnit.isUnit_iff_mulLeft_bijective +@[simp] +theorem mulLeft_one : mulLeft R (1 : A) = LinearMap.id := ext fun _ => one_mul _ @[simp] theorem mulLeft_eq_zero_iff (a : A) : mulLeft R a = 0 ↔ a = 0 := by constructor <;> intro h -- Porting note: had to supply `R` explicitly in `@mulLeft_apply` below - · rw [← mul_one a, ← @mulLeft_apply R _ _ _ _ _ _ a 1, h, LinearMap.zero_apply] + · rw [← mul_one a, ← mulLeft_apply R a 1, h, LinearMap.zero_apply] · rw [h] - exact mulLeft_zero_eq_zero + exact mulLeft_zero_eq_zero _ _ + +@[simp] +theorem pow_mulLeft (a : A) (n : ℕ) : mulLeft R a ^ n = mulLeft R (a ^ n) := + match n with + | 0 => by rw [pow_zero, pow_zero, mulLeft_one, LinearMap.one_eq_id] + | (n + 1) => by rw [pow_succ, pow_succ, mulLeft_mul, LinearMap.mul_eq_comp, pow_mulLeft] + +end left + +section right +variable [Module R A] [IsScalarTower R A A] + +@[simp] +theorem mulRight_one : mulRight R (1 : A) = LinearMap.id := ext fun _ => mul_one _ @[simp] theorem mulRight_eq_zero_iff (a : A) : mulRight R a = 0 ↔ a = 0 := by constructor <;> intro h -- Porting note: had to supply `R` explicitly in `@mulRight_apply` below - · rw [← one_mul a, ← @mulRight_apply R _ _ _ _ _ _ a 1, h, LinearMap.zero_apply] + · rw [← one_mul a, ← mulRight_apply R a 1, h, LinearMap.zero_apply] · rw [h] - exact mulRight_zero_eq_zero + exact mulRight_zero_eq_zero _ _ @[simp] -theorem mulLeft_one : mulLeft R (1 : A) = LinearMap.id := by - ext - simp +theorem pow_mulRight (a : A) (n : ℕ) : mulRight R a ^ n = mulRight R (a ^ n) := + match n with + | 0 => by rw [pow_zero, pow_zero, mulRight_one, LinearMap.one_eq_id] + | (n + 1) => by rw [pow_succ, pow_succ', mulRight_mul, LinearMap.mul_eq_comp, pow_mulRight] -@[simp] -theorem mulRight_one : mulRight R (1 : A) = LinearMap.id := by - ext - simp +end right -@[simp] -theorem pow_mulLeft (a : A) (n : ℕ) : mulLeft R a ^ n = mulLeft R (a ^ n) := by - simpa only [mulLeft, ← Algebra.coe_lmul_eq_mul] using (map_pow (Algebra.lmul R A) a n).symm +end one_side + +variable [CommSemiring R] [Semiring A] [Algebra R A] + +/-- The multiplication in an algebra is an algebra homomorphism into the endomorphisms on +the algebra. + +A weaker version of this for non-unital algebras exists as `NonUnitalAlgHom.lmul`. -/ +def _root_.Algebra.lmul : A →ₐ[R] End R A where + __ := NonUnitalAlgHom.lmul R A + map_one' := mulLeft_one _ _ + commutes' r := ext fun a => (Algebra.smul_def r a).symm + +variable {R A} @[simp] -theorem pow_mulRight (a : A) (n : ℕ) : mulRight R a ^ n = mulRight R (a ^ n) := by - simp only [mulRight, ← Algebra.coe_lmul_eq_mul] - exact - LinearMap.coe_injective (((mulRight R a).coe_pow n).symm ▸ mul_right_iterate a n) +theorem _root_.Algebra.coe_lmul_eq_mul : ⇑(Algebra.lmul R A) = mul R A := + rfl + +theorem _root_.Algebra.lmul_injective : Function.Injective (Algebra.lmul R A) := + fun a₁ a₂ h ↦ by simpa using DFunLike.congr_fun h 1 + +theorem _root_.Algebra.lmul_isUnit_iff {x : A} : + IsUnit (Algebra.lmul R A x) ↔ IsUnit x := by + rw [Module.End_isUnit_iff, Iff.comm] + exact IsUnit.isUnit_iff_mulLeft_bijective theorem toSpanSingleton_eq_algebra_linearMap : toSpanSingleton R A 1 = Algebra.linearMap R A := by ext; simp diff --git a/Mathlib/Algebra/Algebra/Equiv.lean b/Mathlib/Algebra/Algebra/Equiv.lean index cd98b733982f6..37da0ae421201 100644 --- a/Mathlib/Algebra/Algebra/Equiv.lean +++ b/Mathlib/Algebra/Algebra/Equiv.lean @@ -223,11 +223,6 @@ protected theorem map_smul (r : R) (x : A₁) : e (r • x) = r • e x := protected theorem map_pow : ∀ (x : A₁) (n : ℕ), e (x ^ n) = e x ^ n := map_pow _ -@[deprecated map_finsupp_sum (since := "2024-06-20")] -protected theorem map_finsupp_sum {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A₁) : - e (f.sum g) = f.sum fun i b => e (g i b) := - map_finsupp_sum _ _ _ - end map section bijective @@ -742,23 +737,6 @@ instance _root_.Finite.algEquiv [Finite (A₁ →ₐ[R] A₂)] : Finite (A₁ end Semiring -section CommSemiring - -variable [CommSemiring R] [CommSemiring A₁] [CommSemiring A₂] -variable [Algebra R A₁] [Algebra R A₂] (e : A₁ ≃ₐ[R] A₂) - -@[deprecated map_prod (since := "2024-06-20")] -protected theorem map_prod {ι : Type*} (f : ι → A₁) (s : Finset ι) : - e (∏ x ∈ s, f x) = ∏ x ∈ s, e (f x) := - map_prod _ f s - -@[deprecated map_finsupp_prod (since := "2024-06-20")] -protected theorem map_finsupp_prod {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A₁) : - e (f.prod g) = f.prod fun i a => e (g i a) := - map_finsupp_prod _ f g - -end CommSemiring - section Ring variable [CommSemiring R] [Ring A₁] [Ring A₂] diff --git a/Mathlib/Algebra/Algebra/Hom.lean b/Mathlib/Algebra/Algebra/Hom.lean index bdb71967c8292..2640de8265822 100644 --- a/Mathlib/Algebra/Algebra/Hom.lean +++ b/Mathlib/Algebra/Algebra/Hom.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Yury Kudryashov -/ import Mathlib.Algebra.Algebra.Basic -import Mathlib.Algebra.BigOperators.Finsupp /-! # Homomorphisms of `R`-algebras @@ -227,11 +226,6 @@ protected theorem map_sum {ι : Type*} (f : ι → A) (s : Finset ι) : φ (∑ x ∈ s, f x) = ∑ x ∈ s, φ (f x) := map_sum _ _ _ -@[deprecated map_finsupp_sum (since := "2024-06-26")] -protected theorem map_finsupp_sum {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A) : - φ (f.sum g) = f.sum fun i a => φ (g i a) := - map_finsupp_sum _ _ _ - /-- If a `RingHom` is `R`-linear, then it is an `AlgHom`. -/ def mk' (f : A →+* B) (h : ∀ (c : R) (x), f (c • x) = c • f x) : A →ₐ[R] B := { f with @@ -369,27 +363,6 @@ theorem algebraMap_eq_apply (f : A →ₐ[R] B) {y : R} {x : A} (h : algebraMap end Semiring -section CommSemiring - -variable [CommSemiring R] [CommSemiring A] [CommSemiring B] -variable [Algebra R A] [Algebra R B] (φ : A →ₐ[R] B) - -@[deprecated map_multiset_prod (since := "2024-06-26")] -protected theorem map_multiset_prod (s : Multiset A) : φ s.prod = (s.map φ).prod := - map_multiset_prod _ _ - -@[deprecated map_prod (since := "2024-06-26")] -protected theorem map_prod {ι : Type*} (f : ι → A) (s : Finset ι) : - φ (∏ x ∈ s, f x) = ∏ x ∈ s, φ (f x) := - map_prod _ _ _ - -@[deprecated map_finsupp_prod (since := "2024-06-26")] -protected theorem map_finsupp_prod {α : Type*} [Zero α] {ι : Type*} (f : ι →₀ α) (g : ι → α → A) : - φ (f.prod g) = f.prod fun i a => φ (g i a) := - map_finsupp_prod _ _ _ - -end CommSemiring - section Ring variable [CommSemiring R] [Ring A] [Ring B] diff --git a/Mathlib/Algebra/Algebra/Operations.lean b/Mathlib/Algebra/Algebra/Operations.lean index 7c503761b174e..24dddc1deceec 100644 --- a/Mathlib/Algebra/Algebra/Operations.lean +++ b/Mathlib/Algebra/Algebra/Operations.lean @@ -93,24 +93,138 @@ theorem one_le {P : Submodule R A} : (1 : Submodule R A) ≤ P ↔ (1 : A) ∈ P -- Porting note: simpa no longer closes refl goals, so added `SetLike.mem_coe` simp only [one_eq_span, span_le, Set.singleton_subset_iff, SetLike.mem_coe] +variable {M : Type*} [AddCommMonoid M] [Module R M] [Module A M] [IsScalarTower R A M] + +instance : SMul (Submodule R A) (Submodule R M) where + smul A' M' := + { __ := A'.toAddSubmonoid • M'.toAddSubmonoid + smul_mem' := fun r m hm ↦ AddSubmonoid.smul_induction_on hm + (fun a ha m hm ↦ by rw [← smul_assoc]; exact AddSubmonoid.smul_mem_smul (A'.smul_mem r ha) hm) + fun m₁ m₂ h₁ h₂ ↦ by rw [smul_add]; exact (A'.1 • M'.1).add_mem h₁ h₂ } + +section + +variable {I J : Submodule R A} {N P : Submodule R M} + +theorem smul_toAddSubmonoid : (I • N).toAddSubmonoid = I.toAddSubmonoid • N.toAddSubmonoid := rfl + +theorem smul_mem_smul {r} {n} (hr : r ∈ I) (hn : n ∈ N) : r • n ∈ I • N := + AddSubmonoid.smul_mem_smul hr hn + +theorem smul_le : I • N ≤ P ↔ ∀ r ∈ I, ∀ n ∈ N, r • n ∈ P := + AddSubmonoid.smul_le + +@[simp, norm_cast] +lemma coe_set_smul : (I : Set A) • N = I • N := + 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) (smul : ∀ r ∈ I, ∀ n ∈ N, p (r • n)) + (add : ∀ x y, p x → p y → p (x + y)) : p x := + AddSubmonoid.smul_induction_on H smul add + +/-- Dependent version of `Submodule.smul_induction_on`. -/ +@[elab_as_elim] +theorem smul_induction_on' {x : M} (hx : x ∈ I • N) {p : ∀ x, x ∈ I • N → Prop} + (smul : ∀ (r : A) (hr : r ∈ I) (n : M) (hn : n ∈ N), p (r • n) (smul_mem_smul hr hn)) + (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem ‹_› ‹_›)) : p x hx := by + refine Exists.elim ?_ fun (h : x ∈ I • N) (H : p x h) ↦ H + exact smul_induction_on hx (fun a ha x hx ↦ ⟨_, smul _ ha _ hx⟩) + fun x y ⟨_, hx⟩ ⟨_, hy⟩ ↦ ⟨_, add _ _ _ _ hx hy⟩ + +theorem smul_mono (hij : I ≤ J) (hnp : N ≤ P) : I • N ≤ J • P := + AddSubmonoid.smul_le_smul hij hnp + +theorem smul_mono_left (h : I ≤ J) : I • N ≤ J • N := + smul_mono h le_rfl + +instance : CovariantClass (Submodule R A) (Submodule R M) HSMul.hSMul LE.le := + ⟨fun _ _ => smul_mono le_rfl⟩ + +@[deprecated smul_mono_right (since := "2024-03-31")] +protected theorem smul_mono_right (h : N ≤ P) : I • N ≤ I • P := + _root_.smul_mono_right I h + +variable (I J N P) + +@[simp] +theorem smul_bot : I • (⊥ : Submodule R M) = ⊥ := + toAddSubmonoid_injective <| AddSubmonoid.addSubmonoid_smul_bot _ + +@[simp] +theorem bot_smul : (⊥ : Submodule R A) • N = ⊥ := + le_bot_iff.mp <| smul_le.mpr <| by rintro _ rfl _ _; rw [zero_smul]; exact zero_mem _ + +theorem smul_sup : I • (N ⊔ P) = I • N ⊔ I • P := + toAddSubmonoid_injective <| by + simp only [smul_toAddSubmonoid, sup_toAddSubmonoid, AddSubmonoid.addSubmonoid_smul_sup] + +theorem sup_smul : (I ⊔ J) • N = I • N ⊔ J • N := + le_antisymm (smul_le.mpr fun mn hmn p hp ↦ by + obtain ⟨m, hm, n, hn, rfl⟩ := mem_sup.mp hmn + rw [add_smul]; exact add_mem_sup (smul_mem_smul hm hp) <| smul_mem_smul hn hp) + (sup_le (smul_mono_left le_sup_left) <| smul_mono_left le_sup_right) + +protected theorem smul_assoc {B} [Semiring B] [Module R B] [Module A B] [Module B M] + [IsScalarTower R A B] [IsScalarTower R B M] [IsScalarTower A B M] + (I : Submodule R A) (J : Submodule R B) (N : Submodule R M) : + (I • J) • N = I • J • N := + le_antisymm + (smul_le.2 fun _ hrsij t htn ↦ smul_induction_on hrsij + (fun r hr s hs ↦ smul_assoc r s t ▸ smul_mem_smul hr (smul_mem_smul hs htn)) + fun x y ↦ (add_smul x y t).symm ▸ add_mem) + (smul_le.2 fun r hr _ hsn ↦ smul_induction_on hsn + (fun j hj n hn ↦ (smul_assoc r j n).symm ▸ smul_mem_smul (smul_mem_smul hr hj) hn) + fun m₁ m₂ ↦ (smul_add r m₁ m₂) ▸ add_mem) + +@[deprecated smul_inf_le (since := "2024-03-31")] +protected theorem smul_inf_le (M₁ M₂ : Submodule R M) : + I • (M₁ ⊓ M₂) ≤ I • M₁ ⊓ I • M₂ := smul_inf_le _ _ _ + +theorem smul_iSup {ι : Sort*} {I : Submodule R A} {t : ι → Submodule R M} : + I • (⨆ i, t i)= ⨆ i, I • t i := + toAddSubmonoid_injective <| by + simp only [smul_toAddSubmonoid, iSup_toAddSubmonoid, AddSubmonoid.smul_iSup] + +theorem iSup_smul {ι : Sort*} {t : ι → Submodule R A} {N : Submodule R M} : + (⨆ i, t i) • N = ⨆ i, t i • N := + le_antisymm (smul_le.mpr fun t ht s hs ↦ iSup_induction _ (C := (· • s ∈ _)) ht + (fun i t ht ↦ mem_iSup_of_mem i <| smul_mem_smul ht hs) + (by simp_rw [zero_smul]; apply zero_mem) fun x y ↦ by simp_rw [add_smul]; apply add_mem) + (iSup_le fun i ↦ Submodule.smul_mono_left <| le_iSup _ i) + +@[deprecated smul_iInf_le (since := "2024-03-31")] +protected theorem smul_iInf_le {ι : Sort*} {I : Submodule R A} {t : ι → Submodule R M} : + I • iInf t ≤ ⨅ i, I • t i := + smul_iInf_le + +protected theorem one_smul : (1 : Submodule R A) • N = N := by + refine le_antisymm (smul_le.mpr fun r hr m hm ↦ ?_) fun m hm ↦ ?_ + · obtain ⟨r, rfl⟩ := hr + rw [LinearMap.toSpanSingleton_apply, smul_one_smul]; exact N.smul_mem r hm + · rw [← one_smul A m]; exact smul_mem_smul (one_le.mp le_rfl) hm + +theorem smul_subset_smul : (↑I : Set A) • (↑N : Set M) ⊆ (↑(I • N) : Set M) := + AddSubmonoid.smul_subset_smul + +end + variable [IsScalarTower R A A] /-- Multiplication of sub-R-modules of an R-module A that is also a semiring. The submodule `M * N` consists of finite sums of elements `m * n` for `m ∈ M` and `n ∈ N`. -/ instance mul : Mul (Submodule R A) where - mul M N := - { __ := M.toAddSubmonoid * N.toAddSubmonoid - smul_mem' := fun r a ha ↦ AddSubmonoid.mul_induction_on ha - (fun m h n h' ↦ by rw [← smul_mul_assoc]; exact AddSubmonoid.mul_mem_mul (M.smul_mem r h) h') - fun a₁ a₂ h₁ h₂ ↦ by rw [smul_add]; apply (M.1 * N.1).add_mem h₁ h₂ } + mul := (· • ·) variable (S T : Set A) {M N P Q : Submodule R A} {m n : A} theorem mul_mem_mul (hm : m ∈ M) (hn : n ∈ N) : m * n ∈ M * N := - AddSubmonoid.mul_mem_mul hm hn + smul_mem_smul hm hn theorem mul_le : M * N ≤ P ↔ ∀ m ∈ M, ∀ n ∈ N, m * n ∈ P := - AddSubmonoid.mul_le + smul_le theorem mul_toAddSubmonoid (M N : Submodule R A) : (M * N).toAddSubmonoid = M.toAddSubmonoid * N.toAddSubmonoid := rfl @@ -118,46 +232,40 @@ theorem mul_toAddSubmonoid (M N : Submodule R A) : @[elab_as_elim] protected theorem mul_induction_on {C : A → Prop} {r : A} (hr : r ∈ M * N) (hm : ∀ m ∈ M, ∀ n ∈ N, C (m * n)) (ha : ∀ x y, C x → C y → C (x + y)) : C r := - AddSubmonoid.mul_induction_on hr hm ha + smul_induction_on hr hm ha /-- A dependent version of `mul_induction_on`. -/ @[elab_as_elim] protected theorem mul_induction_on' {C : ∀ r, r ∈ M * N → Prop} (mem_mul_mem : ∀ m (hm : m ∈ M) n (hn : n ∈ N), C (m * n) (mul_mem_mul hm hn)) (add : ∀ 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 Submodule.mul_induction_on hr - (fun x hx y hy ↦ ⟨_, mem_mul_mem _ hx _ hy⟩) - fun x y ⟨_, hx⟩ ⟨_, hy⟩ ↦ ⟨_, add _ _ _ _ hx hy⟩ + C r hr := + smul_induction_on' hr mem_mul_mem add variable (M) @[simp] theorem mul_bot : M * ⊥ = ⊥ := - toAddSubmonoid_injective (AddSubmonoid.mul_bot _) + smul_bot _ @[simp] theorem bot_mul : ⊥ * M = ⊥ := - toAddSubmonoid_injective (AddSubmonoid.bot_mul _) + bot_smul _ -protected theorem one_mul : (1 : Submodule R A) * M = M := by - refine le_antisymm (mul_le.mpr fun r hr m hm ↦ ?_) fun m hm ↦ ?_ - · obtain ⟨r, rfl⟩ := hr - rw [LinearMap.toSpanSingleton_apply, smul_one_mul]; exact M.smul_mem r hm - · rw [← one_mul m]; exact mul_mem_mul (one_le.mp le_rfl) hm +protected theorem one_mul : (1 : Submodule R A) * M = M := + Submodule.one_smul _ variable {M} @[mono] theorem mul_le_mul (hmp : M ≤ P) (hnq : N ≤ Q) : M * N ≤ P * Q := - AddSubmonoid.mul_le_mul hmp hnq + smul_mono hmp hnq theorem mul_le_mul_left (h : M ≤ N) : M * P ≤ N * P := - AddSubmonoid.mul_le_mul_left h + smul_mono_left h theorem mul_le_mul_right (h : N ≤ P) : M * N ≤ M * P := - AddSubmonoid.mul_le_mul_right h + smul_mono_right _ h theorem mul_comm_of_commute (h : ∀ m ∈ M, ∀ n ∈ N, Commute m n) : M * N = N * M := toAddSubmonoid_injective <| AddSubmonoid.mul_comm_of_commute h @@ -165,15 +273,13 @@ theorem mul_comm_of_commute (h : ∀ m ∈ M, ∀ n ∈ N, Commute m n) : M * N variable (M N P) theorem mul_sup : M * (N ⊔ P) = M * N ⊔ M * P := - toAddSubmonoid_injective <| by - simp only [mul_toAddSubmonoid, sup_toAddSubmonoid, AddSubmonoid.mul_sup] + smul_sup _ _ _ theorem sup_mul : (M ⊔ N) * P = M * P ⊔ N * P := - toAddSubmonoid_injective <| by - simp only [mul_toAddSubmonoid, sup_toAddSubmonoid, AddSubmonoid.sup_mul] + sup_smul _ _ _ theorem mul_subset_mul : (↑M : Set A) * (↑N : Set A) ⊆ (↑(M * N) : Set A) := - AddSubmonoid.mul_subset_mul + smul_subset_smul _ _ lemma restrictScalars_mul {A B C} [Semiring A] [Semiring B] [Semiring C] [SMul A B] [Module A C] [Module B C] [IsScalarTower A C C] [IsScalarTower B C C] @@ -184,12 +290,10 @@ lemma restrictScalars_mul {A B C} [Semiring A] [Semiring B] [Semiring C] variable {ι : Sort uι} theorem iSup_mul (s : ι → Submodule R A) (t : Submodule R A) : (⨆ i, s i) * t = ⨆ i, s i * t := - toAddSubmonoid_injective <| by - simp only [mul_toAddSubmonoid, iSup_toAddSubmonoid, AddSubmonoid.iSup_mul] + iSup_smul theorem mul_iSup (t : Submodule R A) (s : ι → Submodule R A) : (t * ⨆ i, s i) = ⨆ i, t * s i := - toAddSubmonoid_injective <| by - simp only [mul_toAddSubmonoid, iSup_toAddSubmonoid, AddSubmonoid.mul_iSup] + smul_iSup /-- Sub-`R`-modules of an `R`-module form an idempotent semiring. -/ instance : NonUnitalSemiring (Submodule R A) where diff --git a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean index bf2e80c9aebd3..20f8a381665c2 100644 --- a/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean +++ b/Mathlib/Algebra/Algebra/Subalgebra/Basic.lean @@ -938,6 +938,18 @@ variable (f : A →ₐ[R] B) theorem range_comp_val : (f.comp S.val).range = S.map f := by rw [AlgHom.range_comp, range_val] +/-- An `AlgHom` between two rings restricts to an `AlgHom` from any subalgebra of the +domain onto the image of that subalgebra. -/ +def _root_.AlgHom.subalgebraMap : S →ₐ[R] S.map f := + (f.comp S.val).codRestrict _ fun x ↦ ⟨_, x.2, rfl⟩ + +variable {S} in +@[simp] +theorem _root_.AlgHom.subalgebraMap_coe_apply (x : S) : f.subalgebraMap S x = f x := rfl + +theorem _root_.AlgHom.subalgebraMap_surjective : Function.Surjective (f.subalgebraMap S) := + f.toAddMonoidHom.addSubmonoidMap_surjective S.toAddSubmonoid + variable (hf : Function.Injective f) /-- A subalgebra is isomorphic to its image under an injective `AlgHom` -/ diff --git a/Mathlib/Algebra/AlgebraicCard.lean b/Mathlib/Algebra/AlgebraicCard.lean index 22df4f242969c..c9fce882650c0 100644 --- a/Mathlib/Algebra/AlgebraicCard.lean +++ b/Mathlib/Algebra/AlgebraicCard.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ import Mathlib.Algebra.Polynomial.Cardinal -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Basic /-! ### Cardinality of algebraic numbers diff --git a/Mathlib/Algebra/BigOperators/Associated.lean b/Mathlib/Algebra/BigOperators/Associated.lean index 6f770d8ad564c..e9978f3214640 100644 --- a/Mathlib/Algebra/BigOperators/Associated.lean +++ b/Mathlib/Algebra/BigOperators/Associated.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Jens Wagemaker, Anne Baanen -/ import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Finsupp +import Mathlib.Algebra.Group.Submonoid.Membership /-! # Products of associated, prime, and irreducible elements. diff --git a/Mathlib/Algebra/BigOperators/Finsupp.lean b/Mathlib/Algebra/BigOperators/Finsupp.lean index dffd8f94b48be..fa5e090a17199 100644 --- a/Mathlib/Algebra/BigOperators/Finsupp.lean +++ b/Mathlib/Algebra/BigOperators/Finsupp.lean @@ -6,7 +6,7 @@ Authors: Kenny Lau import Mathlib.Algebra.BigOperators.Pi import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.BigOperators.Fin -import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Data.Finsupp.Fin import Mathlib.Data.Finsupp.Indicator @@ -242,12 +242,10 @@ theorem sum_apply [Zero M] [AddCommMonoid N] {f : α →₀ M} {g : α → M → (f.sum g) a₂ = f.sum fun a₁ b => g a₁ b a₂ := finset_sum_apply _ _ _ --- Porting note: inserted ⇑ on the rhs @[simp, norm_cast] theorem coe_finset_sum [AddCommMonoid N] (S : Finset ι) (f : ι → α →₀ N) : ⇑(∑ i ∈ S, f i) = ∑ i ∈ S, ⇑(f i) := map_sum (coeFnAddHom : (α →₀ N) →+ _) _ _ --- Porting note: inserted ⇑ on the rhs @[simp, norm_cast] theorem coe_sum [Zero M] [AddCommMonoid N] (f : α →₀ M) (g : α → M → β →₀ N) : ⇑(f.sum g) = f.sum fun a₁ b => ⇑(g a₁ b) := coe_finset_sum _ _ @@ -381,14 +379,12 @@ theorem univ_sum_single [Fintype α] [AddCommMonoid M] (f : α →₀ M) : @[simp] theorem univ_sum_single_apply [AddCommMonoid M] [Fintype α] (i : α) (m : M) : ∑ j : α, single i m j = m := by - -- Porting note: rewrite due to leaky classical in lean3 classical rw [single, coe_mk, Finset.sum_pi_single'] simp @[simp] theorem univ_sum_single_apply' [AddCommMonoid M] [Fintype α] (i : α) (m : M) : ∑ j : α, single j m i = m := by - -- Porting note: rewrite due to leaky classical in lean3 simp_rw [single, coe_mk] classical rw [Finset.sum_pi_single] simp @@ -454,7 +450,6 @@ theorem support_sum_eq_biUnion {α : Type*} {ι : Type*} {M : Type*} [DecidableE (h : ∀ i₁ i₂, i₁ ≠ i₂ → Disjoint (g i₁).support (g i₂).support) : (∑ i ∈ s, g i).support = s.biUnion fun i => (g i).support := by classical - -- Porting note: apply Finset.induction_on s was not working; refine does. refine Finset.induction_on s ?_ ?_ · simp · intro i s hi @@ -573,9 +568,11 @@ theorem Finsupp.mul_sum (b : S) (s : α →₀ R) {f : α → R → S} : end +@[simp] lemma Multiset.card_finsuppSum [Zero M] (f : ι →₀ M) (g : ι → M → Multiset α) : + card (f.sum g) = f.sum fun i m ↦ card (g i m) := map_finsupp_sum cardHom .. + namespace Nat --- Porting note: Needed to replace pow with (· ^ ·) /-- If `0 : ℕ` is not in the support of `f : ℕ →₀ ℕ` then `0 < ∏ x ∈ f.support, x ^ (f x)`. -/ theorem prod_pow_pos_of_zero_not_mem_support {f : ℕ →₀ ℕ} (nhf : 0 ∉ f.support) : 0 < f.prod (· ^ ·) := diff --git a/Mathlib/Algebra/BigOperators/Group/Finset.lean b/Mathlib/Algebra/BigOperators/Group/Finset.lean index 282177e1ba7c0..c31cf3896b7ed 100644 --- a/Mathlib/Algebra/BigOperators/Group/Finset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Finset.lean @@ -426,6 +426,13 @@ lemma prod_filter_not_mul_prod_filter (s : Finset α) (p : α → Prop) [Decidab (∏ x ∈ s.filter fun x ↦ ¬p x, f x) * ∏ x ∈ s.filter p, f x = ∏ x ∈ s, f x := by rw [mul_comm, prod_filter_mul_prod_filter_not] +@[to_additive] +theorem prod_filter_xor (p q : α → Prop) [DecidableEq α] [DecidablePred p] [DecidablePred q] : + (∏ x ∈ s with (Xor' (p x) (q x)), f x) = + (∏ x ∈ s with (p x ∧ ¬ q x), f x) * (∏ x ∈ s with (q x ∧ ¬ p x), f x) := by + rw [← prod_union (disjoint_filter_and_not_filter _ _), ← filter_or] + rfl + section ToList @[to_additive (attr := simp)] @@ -1209,8 +1216,7 @@ lemma prod_mulIndicator_subset_of_eq_one [One α] (f : ι → α) (g : ι → α ∏ i ∈ t, g i (mulIndicator ↑s f i) = ∏ i ∈ s, g i (f i) := by calc _ = ∏ i ∈ s, g i (mulIndicator ↑s f i) := by rw [prod_subset h fun i _ hn ↦ by simp [hn, hg]] - -- Porting note: This did not use to need the implicit argument - _ = _ := prod_congr rfl fun i hi ↦ congr_arg _ <| mulIndicator_of_mem (α := ι) hi f + _ = _ := prod_congr rfl fun i hi ↦ congr_arg _ <| mulIndicator_of_mem hi f /-- Taking the product of an indicator function over a possibly larger finset is the same as taking the original function over the original finset. -/ @@ -1241,16 +1247,17 @@ lemma mulIndicator_prod (s : Finset ι) (t : Set κ) (f : ι → κ → β) : variable {κ : Type*} @[to_additive] -lemma mulIndicator_biUnion (s : Finset ι) (t : ι → Set κ) {f : κ → β} : - ((s : Set ι).PairwiseDisjoint t) → - mulIndicator (⋃ i ∈ s, t i) f = fun a ↦ ∏ i ∈ s, mulIndicator (t i) f a := by - classical - refine Finset.induction_on s (by simp) fun i s hi ih hs ↦ funext fun j ↦ ?_ - rw [prod_insert hi, set_biUnion_insert, mulIndicator_union_of_not_mem_inter, - ih (hs.subset <| subset_insert _ _)] - simp only [not_exists, exists_prop, mem_iUnion, mem_inter_iff, not_and] - exact fun hji i' hi' hji' ↦ (ne_of_mem_of_not_mem hi' hi).symm <| - hs.elim_set (mem_insert_self _ _) (mem_insert_of_mem hi') _ hji hji' +lemma mulIndicator_biUnion (s : Finset ι) (t : ι → Set κ) {f : κ → β} + (hs : (s : Set ι).PairwiseDisjoint t) : + mulIndicator (⋃ i ∈ s, t i) f = fun a ↦ ∏ i ∈ s, mulIndicator (t i) f a := by + induction s using Finset.cons_induction with + | empty => simp + | cons i s hi ih => + ext j + rw [coe_cons, Set.pairwiseDisjoint_insert_of_not_mem (Finset.mem_coe.not.2 hi)] at hs + classical + rw [prod_cons, cons_eq_insert, set_biUnion_insert, mulIndicator_union_of_not_mem_inter, ih hs.1] + exact (Set.disjoint_iff.mp (Set.disjoint_iUnion₂_right.mpr hs.2) ·) @[to_additive] lemma mulIndicator_biUnion_apply (s : Finset ι) (t : ι → Set κ) {f : κ → β} @@ -1734,13 +1741,12 @@ theorem prod_pow_boole [DecidableEq α] (s : Finset α) (f : α → β) (a : α) theorem prod_dvd_prod_of_dvd {S : Finset α} (g1 g2 : α → β) (h : ∀ a ∈ S, g1 a ∣ g2 a) : S.prod g1 ∣ S.prod g2 := by - classical - induction S using Finset.induction_on' with - | h₁ => simp - | h₂ _haS _hTS haT IH => - rename_i a T - rw [Finset.prod_insert haT, prod_insert haT] - exact mul_dvd_mul (h a <| T.mem_insert_self a) <| IH fun b hb ↦ h b <| mem_insert_of_mem hb + induction S using Finset.cons_induction with + | empty => simp + | cons a T haT IH => + rw [Finset.prod_cons, Finset.prod_cons] + rw [Finset.forall_mem_cons] at h + exact mul_dvd_mul h.1 <| IH h.2 theorem prod_dvd_prod_of_subset {ι M : Type*} [CommMonoid M] (s t : Finset ι) (f : ι → M) (h : s ⊆ t) : (∏ i ∈ s, f i) ∣ ∏ i ∈ t, f i := @@ -1887,10 +1893,9 @@ theorem card_eq_sum_card_image [DecidableEq β] (f : α → β) (s : Finset α) theorem mem_sum {f : α → Multiset β} (s : Finset α) (b : β) : (b ∈ ∑ x ∈ s, f x) ↔ ∃ a ∈ s, b ∈ f a := by - classical - refine s.induction_on (by simp) ?_ - intro a t hi ih - simp [sum_insert hi, ih, or_and_right, exists_or] + induction s using Finset.cons_induction with + | empty => simp + | cons a t hi ih => simp [sum_cons, ih, or_and_right, exists_or] @[to_additive] theorem prod_unique_nonempty {α β : Type*} [CommMonoid β] [Unique α] (s : Finset α) (f : α → β) @@ -2083,6 +2088,10 @@ end List namespace Multiset +@[simp] +lemma card_sum (s : Finset ι) (f : ι → Multiset α) : card (∑ i ∈ s, f i) = ∑ i ∈ s, card (f i) := + map_sum cardHom .. + theorem disjoint_list_sum_left {a : Multiset α} {l : List (Multiset α)} : Disjoint l.sum a ↔ ∀ b ∈ l, Disjoint b a := by induction l with @@ -2162,11 +2171,9 @@ theorem toFinset_prod_dvd_prod [CommMonoid α] (S : Multiset α) : S.toFinset.pr @[to_additive] theorem prod_sum {α : Type*} {ι : Type*} [CommMonoid α] (f : ι → Multiset α) (s : Finset ι) : (∑ x ∈ s, f x).prod = ∏ x ∈ s, (f x).prod := by - classical - induction s using Finset.induction_on with - | empty => rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero] - | insert hat ih => - rw [Finset.sum_insert hat, Finset.prod_insert hat, Multiset.prod_add, ih] + induction s using Finset.cons_induction with + | empty => rw [Finset.sum_empty, Finset.prod_empty, Multiset.prod_zero] + | cons a s has ih => rw [Finset.sum_cons, Finset.prod_cons, Multiset.prod_add, ih] end Multiset @@ -2175,14 +2182,23 @@ theorem Units.coe_prod {M : Type*} [CommMonoid M] (f : α → Mˣ) (s : Finset (↑(∏ i ∈ s, f i) : M) = ∏ i ∈ s, (f i : M) := map_prod (Units.coeHom M) _ _ +@[to_additive (attr := simp)] +lemma IsUnit.prod_iff [CommMonoid β] : IsUnit (∏ a ∈ s, f a) ↔ ∀ a ∈ s, IsUnit (f a) := by + induction s using Finset.cons_induction with + | empty => simp + | cons a s ha hs => rw [Finset.prod_cons, IsUnit.mul_iff, hs, Finset.forall_mem_cons] + +@[to_additive] +lemma IsUnit.prod_univ_iff [Fintype α] [CommMonoid β] : IsUnit (∏ a, f a) ↔ ∀ a, IsUnit (f a) := by + simp + theorem nat_abs_sum_le {ι : Type*} (s : Finset ι) (f : ι → ℤ) : (∑ i ∈ s, f i).natAbs ≤ ∑ i ∈ s, (f i).natAbs := by - classical - induction s using Finset.induction_on with - | empty => simp only [Finset.sum_empty, Int.natAbs_zero, le_refl] - | insert his IH => - simp only [his, Finset.sum_insert, not_false_iff] - exact (Int.natAbs_add_le _ _).trans (Nat.add_le_add_left IH _) + induction s using Finset.cons_induction with + | empty => simp only [Finset.sum_empty, Int.natAbs_zero, le_refl] + | cons i s his IH => + simp only [Finset.sum_cons, not_false_iff] + exact (Int.natAbs_add_le _ _).trans (Nat.add_le_add_left IH _) /-! ### `Additive`, `Multiplicative` -/ diff --git a/Mathlib/Algebra/BigOperators/Group/List.lean b/Mathlib/Algebra/BigOperators/Group/List.lean index 2bd6c8a351d66..0eb24a9825d47 100644 --- a/Mathlib/Algebra/BigOperators/Group/List.lean +++ b/Mathlib/Algebra/BigOperators/Group/List.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Floris van Doorn, Sébastien Gouëzel, Alex J. Best -/ import Mathlib.Algebra.Divisibility.Basic import Mathlib.Algebra.Group.Int +import Mathlib.Data.List.Lemmas import Mathlib.Data.List.Dedup import Mathlib.Data.List.Flatten import Mathlib.Data.List.Pairwise @@ -205,7 +206,8 @@ theorem prod_take_mul_prod_drop (L : List M) (i : ℕ) : @[to_additive (attr := simp)] theorem prod_take_succ (L : List M) (i : ℕ) (p : i < L.length) : (L.take (i + 1)).prod = (L.take i).prod * L[i] := by - simp [← take_concat_get', p] + rw [← take_concat_get' _ _ p, prod_append] + simp /-- A list with product not one must have positive length. -/ @[to_additive "A list with sum not zero must have positive length."] @@ -386,10 +388,10 @@ lemma prod_map_ite (p : α → Prop) [DecidablePred p] (f g : α → M) (l : Lis rw [ih] clear ih by_cases hx : p x - · simp only [hx, ↓reduceIte, decide_not, decide_True, map_cons, prod_cons, not_true_eq_false, - decide_False, Bool.false_eq_true, mul_assoc] - · simp only [hx, ↓reduceIte, decide_not, decide_False, Bool.false_eq_true, not_false_eq_true, - decide_True, map_cons, prod_cons, mul_left_comm] + · simp only [hx, ↓reduceIte, decide_not, decide_true, map_cons, prod_cons, not_true_eq_false, + decide_false, Bool.false_eq_true, mul_assoc] + · simp only [hx, ↓reduceIte, decide_not, decide_false, Bool.false_eq_true, not_false_eq_true, + decide_true, map_cons, prod_cons, mul_left_comm] @[to_additive] lemma prod_map_filter_mul_prod_map_filter_not (p : α → Prop) [DecidablePred p] (f : α → M) @@ -660,22 +662,10 @@ lemma mem_mem_ranges_iff_lt_sum (l : List ℕ) {n : ℕ} : (∃ s ∈ l.ranges, n ∈ s) ↔ n < l.sum := by rw [← mem_range, ← ranges_flatten, mem_flatten] -@[simp] -theorem length_flatMap (l : List α) (f : α → List β) : - length (List.flatMap l f) = sum (map (length ∘ f) l) := by - rw [List.flatMap, length_flatten, map_map] - @[deprecated (since := "2024-10-16")] alias length_bind := length_flatMap -lemma countP_flatMap (p : β → Bool) (l : List α) (f : α → List β) : - countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by - rw [List.flatMap, countP_flatten, map_map] - @[deprecated (since := "2024-10-16")] alias countP_bind := countP_flatMap -lemma count_flatMap [BEq β] (l : List α) (f : α → List β) (x : β) : - count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap _ _ _ - @[deprecated (since := "2024-10-16")] alias count_bind := count_flatMap /-- In a flatten, taking the first elements up to an index which is the sum of the lengths of the diff --git a/Mathlib/Algebra/BigOperators/Group/Multiset.lean b/Mathlib/Algebra/BigOperators/Group/Multiset.lean index a0bb921c056e3..a93afea870a07 100644 --- a/Mathlib/Algebra/BigOperators/Group/Multiset.lean +++ b/Mathlib/Algebra/BigOperators/Group/Multiset.lean @@ -187,7 +187,6 @@ theorem prod_induction (p : α → Prop) (s : Multiset α) (p_mul : ∀ a b, p a @[to_additive] theorem prod_induction_nonempty (p : α → Prop) (p_mul : ∀ a b, p a → p b → p (a * b)) (hs : s ≠ ∅) (p_s : ∀ a ∈ s, p a) : p s.prod := by - -- Porting note: used to be `refine' Multiset.induction _ _` induction s using Multiset.induction_on with | empty => simp at hs | cons a s hsa => @@ -263,8 +262,7 @@ theorem prod_map_inv' (m : Multiset α) : (m.map Inv.inv).prod = m.prod⁻¹ := @[to_additive (attr := simp)] theorem prod_map_inv : (m.map fun i => (f i)⁻¹).prod = (m.map f).prod⁻¹ := by - -- Porting note: used `convert` - simp_rw [← (m.map f).prod_map_inv', map_map, Function.comp_apply] + rw [← (m.map f).prod_map_inv', map_map, Function.comp_def] @[to_additive (attr := simp)] theorem prod_map_div : (m.map fun i => f i / g i).prod = (m.map f).prod / (m.map g).prod := diff --git a/Mathlib/Algebra/BigOperators/Module.lean b/Mathlib/Algebra/BigOperators/Module.lean index 2329df72948f4..37171b85f8437 100644 --- a/Mathlib/Algebra/BigOperators/Module.lean +++ b/Mathlib/Algebra/BigOperators/Module.lean @@ -41,6 +41,13 @@ theorem sum_Ico_by_parts (hmn : m < n) : simp_rw [this, sum_neg_distrib, sum_range_succ, smul_add] abel +theorem sum_Ioc_by_parts (hmn : m < n) : + ∑ i ∈ Ioc m n, f i • g i = + f n • G (n + 1) - f (m + 1) • G (m + 1) + - ∑ i ∈ Ioc m (n - 1), (f (i + 1) - f i) • G (i + 1) := by + simpa only [← Nat.Ico_succ_succ, Nat.succ_eq_add_one, Nat.sub_add_cancel (Nat.one_le_of_lt hmn), + add_tsub_cancel_right] using sum_Ico_by_parts f g (Nat.succ_lt_succ hmn) + variable (n) /-- **Summation by parts** for ranges -/ diff --git a/Mathlib/Algebra/BigOperators/Ring.lean b/Mathlib/Algebra/BigOperators/Ring.lean index ff6ed790f07e8..6e86cf047cd5e 100644 --- a/Mathlib/Algebra/BigOperators/Ring.lean +++ b/Mathlib/Algebra/BigOperators/Ring.lean @@ -178,6 +178,14 @@ theorem prod_add (f g : ι → α) (s : Finset ι) : simp only [mem_filter, mem_sdiff, not_and, not_exists, and_congr_right_iff] tauto) +theorem prod_one_add {f : ι → α} (s : Finset ι) : + ∏ i ∈ s, (1 + f i) = ∑ t ∈ s.powerset, ∏ i ∈ t, f i := by + simp only [add_comm (1 : α), prod_add, prod_const_one, mul_one] + +theorem prod_add_one {f : ι → α} (s : Finset ι) : + ∏ i ∈ s, (f i + 1) = ∑ t ∈ s.powerset, ∏ i ∈ t, f i := by + simp only [prod_add, prod_const_one, mul_one] + end DecidableEq /-- `∏ i, (f i + g i) = (∏ i, f i) + ∑ i, g i * (∏ j < i, f j + g j) * (∏ j > i, f j)`. -/ @@ -266,6 +274,10 @@ end CommRing section DivisionSemiring variable [DivisionSemiring α] +lemma _root_.Multiset.sum_map_div {s : Multiset ι} {f : ι → α} {a : α} : + (s.map (fun x ↦ f x / a)).sum = (s.map f).sum / a := by + simp only [div_eq_mul_inv, Multiset.sum_map_mul_right] + lemma sum_div (s : Finset ι) (f : ι → α) (a : α) : (∑ i ∈ s, f i) / a = ∑ i ∈ s, f i / a := by simp only [div_eq_mul_inv, sum_mul] diff --git a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean index 1053dac09d757..1f4d18462f038 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Basic.lean @@ -153,7 +153,7 @@ instance hasForgetToRing : HasForget₂ (AlgebraCat.{v} R) RingCat.{v} where instance hasForgetToModule : HasForget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R) where forget₂ := { obj := fun M => ModuleCat.of R M - map := fun f => ModuleCat.asHom f.hom.toLinearMap } + map := fun f => ModuleCat.ofHom f.hom.toLinearMap } @[simp] lemma forget₂_module_obj (X : AlgebraCat.{v} R) : @@ -162,7 +162,7 @@ lemma forget₂_module_obj (X : AlgebraCat.{v} R) : @[simp] lemma forget₂_module_map {X Y : AlgebraCat.{v} R} (f : X ⟶ Y) : - (forget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R)).map f = ModuleCat.asHom f.hom.toLinearMap := + (forget₂ (AlgebraCat.{v} R) (ModuleCat.{v} R)).map f = ModuleCat.ofHom f.hom.toLinearMap := rfl variable {R} in diff --git a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean index fa16a8aac4bcd..48a1d4c9ff2f5 100644 --- a/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean +++ b/Mathlib/Algebra/Category/AlgebraCat/Monoidal.lean @@ -60,9 +60,10 @@ noncomputable instance instMonoidalCategory : MonoidalCategory (AlgebraCat.{u} R (forget₂ (AlgebraCat R) (ModuleCat R)) { μIso := fun _ _ => Iso.refl _ εIso := Iso.refl _ - associator_eq := fun _ _ _ => TensorProduct.ext_threefold (fun _ _ _ => rfl) - leftUnitor_eq := fun _ => TensorProduct.ext' (fun _ _ => rfl) - rightUnitor_eq := fun _ => TensorProduct.ext' (fun _ _ => rfl) } + associator_eq := fun _ _ _ => + ModuleCat.hom_ext <| TensorProduct.ext_threefold (fun _ _ _ => rfl) + leftUnitor_eq := fun _ => ModuleCat.hom_ext <| TensorProduct.ext' (fun _ _ => rfl) + rightUnitor_eq := fun _ => ModuleCat.hom_ext <| TensorProduct.ext' (fun _ _ => rfl) } /-- `forget₂ (AlgebraCat R) (ModuleCat R)` as a monoidal functor. -/ example : (forget₂ (AlgebraCat R) (ModuleCat R)).Monoidal := inferInstance diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean index 3d24b8db74884..362312b348546 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/Basic.lean @@ -46,8 +46,9 @@ variable (R) /-- The object in the category of `R`-coalgebras associated to an `R`-coalgebra. -/ @[simps] def of (X : Type v) [AddCommGroup X] [Module R X] [Coalgebra R X] : - CoalgebraCat R where - instCoalgebra := (inferInstance : Coalgebra R X) + CoalgebraCat R := + { ModuleCat.of R X with + instCoalgebra := (inferInstance : Coalgebra R X) } variable {R} @@ -105,7 +106,7 @@ instance concreteCategory : ConcreteCategory.{v} (CoalgebraCat.{v} R) where instance hasForgetToModule : HasForget₂ (CoalgebraCat R) (ModuleCat R) where forget₂ := { obj := fun M => ModuleCat.of R M - map := fun f => f.toCoalgHom.toLinearMap } + map := fun f => ModuleCat.ofHom f.toCoalgHom.toLinearMap } @[simp] theorem forget₂_obj (X : CoalgebraCat R) : @@ -114,7 +115,7 @@ theorem forget₂_obj (X : CoalgebraCat R) : @[simp] theorem forget₂_map (X Y : CoalgebraCat R) (f : X ⟶ Y) : - (forget₂ (CoalgebraCat R) (ModuleCat R)).map f = (f.toCoalgHom : X →ₗ[R] Y) := + (forget₂ (CoalgebraCat R) (ModuleCat R)).map f = ModuleCat.ofHom (f.toCoalgHom : X →ₗ[R] Y) := rfl end CoalgebraCat diff --git a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean index c150eabdf07e7..51ff35c7035db 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/ComonEquivalence.lean @@ -36,13 +36,13 @@ open CategoryTheory MonoidalCategory variable {R : Type u} [CommRing R] /-- An `R`-coalgebra is a comonoid object in the category of `R`-modules. -/ -@[simps] def toComonObj (X : CoalgebraCat R) : Comon_ (ModuleCat R) where +@[simps X counit comul] def toComonObj (X : CoalgebraCat R) : Comon_ (ModuleCat R) where X := ModuleCat.of R X - counit := ModuleCat.asHom Coalgebra.counit - comul := ModuleCat.asHom Coalgebra.comul - counit_comul := by simpa only [ModuleCat.of_coe] using Coalgebra.rTensor_counit_comp_comul - comul_counit := by simpa only [ModuleCat.of_coe] using Coalgebra.lTensor_counit_comp_comul - comul_assoc := by simp_rw [ModuleCat.of_coe]; exact Coalgebra.coassoc.symm + counit := ModuleCat.ofHom Coalgebra.counit + comul := ModuleCat.ofHom Coalgebra.comul + counit_comul := ModuleCat.hom_ext <| by simpa using Coalgebra.rTensor_counit_comp_comul + comul_counit := ModuleCat.hom_ext <| by simpa using Coalgebra.lTensor_counit_comp_comul + comul_assoc := ModuleCat.hom_ext <| by simp_rw [ModuleCat.of_coe]; exact Coalgebra.coassoc.symm variable (R) in /-- The natural functor from `R`-coalgebras to comonoid objects in the category of `R`-modules. -/ @@ -50,27 +50,27 @@ variable (R) in def toComon : CoalgebraCat R ⥤ Comon_ (ModuleCat R) where obj X := toComonObj X map f := - { hom := ModuleCat.asHom f.1 - hom_counit := f.1.counit_comp - hom_comul := f.1.map_comp_comul.symm } + { hom := ModuleCat.ofHom f.1 + hom_counit := ModuleCat.hom_ext f.1.counit_comp + hom_comul := ModuleCat.hom_ext f.1.map_comp_comul.symm } /-- A comonoid object in the category of `R`-modules has a natural comultiplication and counit. -/ @[simps] instance ofComonObjCoalgebraStruct (X : Comon_ (ModuleCat R)) : CoalgebraStruct R X.X where - comul := X.comul - counit := X.counit + comul := X.comul.hom + counit := X.counit.hom /-- A comonoid object in the category of `R`-modules has a natural `R`-coalgebra structure. -/ -def ofComonObj (X : Comon_ (ModuleCat R)) : CoalgebraCat R where - carrier := X.X - instCoalgebra := - { ofComonObjCoalgebraStruct X with - coassoc := X.comul_assoc.symm - rTensor_counit_comp_comul := X.counit_comul - lTensor_counit_comp_comul := X.comul_counit } +def ofComonObj (X : Comon_ (ModuleCat R)) : CoalgebraCat R := + { ModuleCat.of R X.X with + instCoalgebra := + { ofComonObjCoalgebraStruct X with + coassoc := ModuleCat.hom_ext_iff.mp X.comul_assoc.symm + rTensor_counit_comp_comul := ModuleCat.hom_ext_iff.mp X.counit_comul + lTensor_counit_comp_comul := ModuleCat.hom_ext_iff.mp X.comul_counit } } variable (R) @@ -79,9 +79,9 @@ def ofComon : Comon_ (ModuleCat R) ⥤ CoalgebraCat R where obj X := ofComonObj X map f := { toCoalgHom := - { f.hom with - counit_comp := f.hom_counit - map_comp_comul := f.hom_comul.symm }} + { f.hom.hom with + counit_comp := ModuleCat.hom_ext_iff.mp f.hom_counit + map_comp_comul := ModuleCat.hom_ext_iff.mp f.hom_comul.symm }} /-- The natural category equivalence between `R`-coalgebras and comonoid objects in the category of `R`-modules. -/ diff --git a/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean index dbd37c50e0b59..be3ac68381c8e 100644 --- a/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean +++ b/Mathlib/Algebra/Category/CoalgebraCat/Monoidal.lean @@ -50,9 +50,9 @@ noncomputable def MonoidalCategory.inducingFunctorData : whiskerRight_eq X f := by ext; rfl tensorHom_eq f g := by ext; rfl εIso := Iso.refl _ - associator_eq X Y Z := TensorProduct.ext <| TensorProduct.ext <| by ext; rfl - leftUnitor_eq X := TensorProduct.ext <| by ext; rfl - rightUnitor_eq X := TensorProduct.ext <| by ext; rfl + associator_eq X Y Z := ModuleCat.hom_ext <| TensorProduct.ext <| TensorProduct.ext <| by ext; rfl + leftUnitor_eq X := ModuleCat.hom_ext <| TensorProduct.ext <| by ext; rfl + rightUnitor_eq X := ModuleCat.hom_ext <| TensorProduct.ext <| by ext; rfl noncomputable instance instMonoidalCategory : MonoidalCategory (CoalgebraCat R) := Monoidal.induced (forget₂ _ (ModuleCat R)) (MonoidalCategory.inducingFunctorData R) diff --git a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean index e6577b9339afb..07f1ca89ad5e6 100644 --- a/Mathlib/Algebra/Category/FGModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/FGModuleCat/Basic.lean @@ -72,12 +72,6 @@ instance : LargeCategory (FGModuleCat R) := by dsimp [FGModuleCat] infer_instance -instance {M N : FGModuleCat R} : FunLike (M ⟶ N) M N := - LinearMap.instFunLike - -instance {M N : FGModuleCat R} : LinearMapClass (M ⟶ N) R M N := - LinearMap.semilinearMapClass - instance : ConcreteCategory (FGModuleCat R) := by dsimp [FGModuleCat] infer_instance @@ -101,9 +95,20 @@ instance : Inhabited (FGModuleCat R) := ⟨⟨ModuleCat.of R R, Module.Finite.self R⟩⟩ /-- Lift an unbundled finitely generated module to `FGModuleCat R`. -/ -def of (V : Type u) [AddCommGroup V] [Module R V] [Module.Finite R V] : FGModuleCat R := +abbrev of (V : Type u) [AddCommGroup V] [Module R V] [Module.Finite R V] : FGModuleCat R := ⟨ModuleCat.of R V, by change Module.Finite R V; infer_instance⟩ +variable {R} in +/-- Lift a linear map between finitely generated modules to `FGModuleCat R`. -/ +abbrev ofHom {V W : Type u} [AddCommGroup V] [Module R V] [Module.Finite R V] + [AddCommGroup W] [Module R W] [Module.Finite R W] + (f : V →ₗ[R] W) : of R V ⟶ of R W := + ModuleCat.ofHom f + +variable {R} in +@[ext] lemma hom_ext {V W : FGModuleCat R} {f g : V ⟶ W} (h : f.hom = g.hom) : f = g := + ModuleCat.hom_ext h + instance (V : FGModuleCat R) : Module.Finite R V := V.property @@ -127,8 +132,8 @@ def _root_.LinearEquiv.toFGModuleCatIso {V W : Type u} [AddCommGroup V] [Module R V] [Module.Finite R V] [AddCommGroup W] [Module R W] [Module.Finite R W] (e : V ≃ₗ[R] W) : FGModuleCat.of R V ≅ FGModuleCat.of R W where - hom := e.toLinearMap - inv := e.symm.toLinearMap + hom := ModuleCat.ofHom e.toLinearMap + inv := ModuleCat.ofHom e.symm.toLinearMap hom_inv_id := by ext x; exact e.left_inv x inv_hom_id := by ext x; exact e.right_inv x @@ -176,7 +181,11 @@ instance : (forget₂ (FGModuleCat.{u} R) (ModuleCat.{u} R)).Additive where instance : (forget₂ (FGModuleCat.{u} R) (ModuleCat.{u} R)).Linear R where theorem Iso.conj_eq_conj {V W : FGModuleCat R} (i : V ≅ W) (f : End V) : - Iso.conj i f = LinearEquiv.conj (isoToLinearEquiv i) f := + Iso.conj i f = FGModuleCat.ofHom (LinearEquiv.conj (isoToLinearEquiv i) f.hom) := + rfl + +theorem Iso.conj_hom_eq_conj {V W : FGModuleCat R} (i : V ≅ W) (f : End V) : + (Iso.conj i f).hom = (LinearEquiv.conj (isoToLinearEquiv i) f.hom) := rfl end CommRing @@ -186,11 +195,12 @@ section Field variable (K : Type u) [Field K] instance (V W : FGModuleCat K) : Module.Finite K (V ⟶ W) := - (by infer_instance : Module.Finite K (V →ₗ[K] W)) + (inferInstanceAs <| Module.Finite K (V →ₗ[K] W)).equiv ModuleCat.homLinearEquiv.symm instance closedPredicateModuleFinite : MonoidalCategory.ClosedPredicate fun V : ModuleCat.{u} K ↦ Module.Finite K V where - prop_ihom {X Y} _ _ := Module.Finite.linearMap K K X Y + prop_ihom {X Y} _ _ := + (inferInstanceAs <| Module.Finite K (X →ₗ[K] Y)).equiv ModuleCat.homLinearEquiv.symm instance : MonoidalClosed (FGModuleCat K) := by dsimp [FGModuleCat] @@ -201,7 +211,7 @@ instance : MonoidalClosed (FGModuleCat K) := by variable (V W : FGModuleCat K) @[simp] -theorem ihom_obj : (ihom V).obj W = FGModuleCat.of K (V →ₗ[K] W) := +theorem ihom_obj : (ihom V).obj W = FGModuleCat.of K (V ⟶ W) := rfl /-- The dual module is the dual in the rigid monoidal category `FGModuleCat K`. -/ @@ -216,33 +226,43 @@ open CategoryTheory.MonoidalCategory /-- The coevaluation map is defined in `LinearAlgebra.coevaluation`. -/ def FGModuleCatCoevaluation : 𝟙_ (FGModuleCat K) ⟶ V ⊗ FGModuleCatDual K V := - coevaluation K V + ModuleCat.ofHom <| coevaluation K V theorem FGModuleCatCoevaluation_apply_one : - FGModuleCatCoevaluation K V (1 : K) = + (FGModuleCatCoevaluation K V).hom (1 : K) = ∑ i : Basis.ofVectorSpaceIndex K V, (Basis.ofVectorSpace K V) i ⊗ₜ[K] (Basis.ofVectorSpace K V).coord i := coevaluation_apply_one K V /-- The evaluation morphism is given by the contraction map. -/ def FGModuleCatEvaluation : FGModuleCatDual K V ⊗ V ⟶ 𝟙_ (FGModuleCat K) := - contractLeft K V + ModuleCat.ofHom <| contractLeft K V -@[simp] theorem FGModuleCatEvaluation_apply (f : FGModuleCatDual K V) (x : V) : - (FGModuleCatEvaluation K V) (f ⊗ₜ x) = f.toFun x := + (FGModuleCatEvaluation K V).hom (f ⊗ₜ x) = f.toFun x := + contractLeft_apply f x + +/-- `@[simp]`-normal form of `FGModuleCatEvaluation_apply`, where the carriers have been unfolded. +-/ +@[simp] +theorem FGModuleCatEvaluation_apply' (f : FGModuleCatDual K V) (x : V) : + DFunLike.coe + (F := ((ModuleCat.of K (Module.Dual K V) ⊗ V.obj).carrier →ₗ[K] (𝟙_ (ModuleCat K)))) + (FGModuleCatEvaluation K V).hom (f ⊗ₜ x) = f.toFun x := contractLeft_apply f x private theorem coevaluation_evaluation : letI V' : FGModuleCat K := FGModuleCatDual K V V' ◁ FGModuleCatCoevaluation K V ≫ (α_ V' V V').inv ≫ FGModuleCatEvaluation K V ▷ V' = (ρ_ V').hom ≫ (λ_ V').inv := by + ext : 1 apply contractLeft_assoc_coevaluation K V private theorem evaluation_coevaluation : FGModuleCatCoevaluation K V ▷ V ≫ (α_ V (FGModuleCatDual K V) V).hom ≫ V ◁ FGModuleCatEvaluation K V = (λ_ V).hom ≫ (ρ_ V).inv := by + ext : 1 apply contractLeft_assoc_coevaluation' K V instance exactPairing : ExactPairing V (FGModuleCatDual K V) where @@ -266,9 +286,10 @@ end FGModuleCat @[simp] theorem LinearMap.comp_id_fgModuleCat {R} [Ring R] {G : FGModuleCat.{u} R} {H : Type u} [AddCommGroup H] [Module R H] - (f : G →ₗ[R] H) : f.comp (𝟙 G) = f := - Category.id_comp (ModuleCat.asHom f) + (f : G →ₗ[R] H) : f.comp (ModuleCat.Hom.hom (𝟙 G)) = f := + ModuleCat.hom_ext_iff.mp <| Category.id_comp (ModuleCat.ofHom f) + @[simp] theorem LinearMap.id_fgModuleCat_comp {R} [Ring R] {G : Type u} [AddCommGroup G] [Module R G] {H : FGModuleCat.{u} R} - (f : G →ₗ[R] H) : LinearMap.comp (𝟙 H) f = f := - Category.comp_id (ModuleCat.asHom f) + (f : G →ₗ[R] H) : LinearMap.comp (ModuleCat.Hom.hom (𝟙 H)) f = f := + ModuleCat.hom_ext_iff.mp <| Category.comp_id (ModuleCat.ofHom f) diff --git a/Mathlib/Algebra/Category/FGModuleCat/Limits.lean b/Mathlib/Algebra/Category/FGModuleCat/Limits.lean index 3e5af1918343b..7b88d667c1bdb 100644 --- a/Mathlib/Algebra/Category/FGModuleCat/Limits.lean +++ b/Mathlib/Algebra/Category/FGModuleCat/Limits.lean @@ -38,7 +38,7 @@ variable {k : Type v} [Field k] instance {J : Type} [Finite J] (Z : J → ModuleCat.{v} k) [∀ j, FiniteDimensional k (Z j)] : FiniteDimensional k (∏ᶜ fun j => Z j : ModuleCat.{v} k) := haveI : FiniteDimensional k (ModuleCat.of k (∀ j, Z j)) := by unfold ModuleCat.of; infer_instance - FiniteDimensional.of_injective (ModuleCat.piIsoPi _).hom + FiniteDimensional.of_injective (ModuleCat.piIsoPi _).hom.hom ((ModuleCat.mono_iff_injective _).1 (by infer_instance)) /-- Finite limits of finite dimensional vectors spaces are finite dimensional, @@ -48,7 +48,7 @@ instance (F : J ⥤ FGModuleCat k) : haveI : ∀ j, FiniteDimensional k ((F ⋙ forget₂ (FGModuleCat k) (ModuleCat.{v} k)).obj j) := by intro j; change FiniteDimensional k (F.obj j); infer_instance FiniteDimensional.of_injective - (limitSubobjectProduct (F ⋙ forget₂ (FGModuleCat k) (ModuleCat.{v} k))) + (limitSubobjectProduct (F ⋙ forget₂ (FGModuleCat k) (ModuleCat.{v} k))).hom ((ModuleCat.mono_iff_injective _).1 inferInstance) /-- The forgetful functor from `FGModuleCat k` to `ModuleCat k` creates all finite limits. -/ diff --git a/Mathlib/Algebra/Category/Grp/AB5.lean b/Mathlib/Algebra/Category/Grp/AB5.lean index a5230f8bf90ff..81a72475dbf30 100644 --- a/Mathlib/Algebra/Category/Grp/AB5.lean +++ b/Mathlib/Algebra/Category/Grp/AB5.lean @@ -3,14 +3,9 @@ Copyright (c) 2023 David Kurniadi Angdinata. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Kurniadi Angdinata, Moritz Firsching, Nikolas Kuhn, Amelia Livingston -/ - -import Mathlib.Algebra.Homology.ShortComplex.Ab -import Mathlib.Algebra.Homology.ShortComplex.ExactFunctor -import Mathlib.CategoryTheory.Abelian.Exact import Mathlib.Algebra.Category.Grp.FilteredColimits -import Mathlib.CategoryTheory.Abelian.FunctorCategory +import Mathlib.Algebra.Homology.ShortComplex.Ab import Mathlib.CategoryTheory.Abelian.GrothendieckAxioms - /-! # The category of abelian groups satisfies Grothendieck's axiom AB5 @@ -51,4 +46,4 @@ instance : HasFilteredColimits (AddCommGrp.{u}) where HasColimitsOfShape := inferInstance noncomputable instance : AB5 (AddCommGrp.{u}) where - preservesFiniteLimits := fun _ => inferInstance + ofShape _ := { preservesFiniteLimits := inferInstance } diff --git a/Mathlib/Algebra/Category/Grp/Colimits.lean b/Mathlib/Algebra/Category/Grp/Colimits.lean index ffd0441416766..1164b843e4f0b 100644 --- a/Mathlib/Algebra/Category/Grp/Colimits.lean +++ b/Mathlib/Algebra/Category/Grp/Colimits.lean @@ -209,8 +209,7 @@ def descFun (s : Cocone F) : ColimitType.{w} F → s.pt := by def descMorphism (s : Cocone F) : colimit.{w} F ⟶ s.pt where toFun := descFun F s map_zero' := rfl - -- Porting note: in `mathlib3`, nothing needs to be done after `induction` - map_add' x y := Quot.induction_on₂ x y fun _ _ => by dsimp; rw [← quot_add F]; rfl + map_add' x y := Quot.induction_on₂ x y fun _ _ ↦ rfl /-- Evidence that the proposed colimit is the colimit. -/ def colimitCoconeIsColimit : IsColimit (colimitCocone.{w} F) where diff --git a/Mathlib/Algebra/Category/Grp/EpiMono.lean b/Mathlib/Algebra/Category/Grp/EpiMono.lean index 308229317d4be..b1252eb15d7cd 100644 --- a/Mathlib/Algebra/Category/Grp/EpiMono.lean +++ b/Mathlib/Algebra/Category/Grp/EpiMono.lean @@ -88,13 +88,12 @@ theorem mono_iff_injective : Mono f ↔ Function.Injective f := namespace SurjectiveOfEpiAuxs -set_option quotPrecheck false in -local notation "X" => Set.range (· • (f.range : Set B) : B → Set B) +local notation3 "X" => Set.range (· • (f.range : Set B) : B → Set B) /-- Define `X'` to be the set of all left cosets with an extra point at "infinity". -/ inductive XWithInfinity - | fromCoset : Set.range (· • (f.range : Set B) : B → Set B) → XWithInfinity + | fromCoset : X → XWithInfinity | infinity : XWithInfinity open XWithInfinity Equiv.Perm @@ -222,7 +221,7 @@ The strategy is the following: assuming `epi f` -/ -theorem g_apply_fromCoset (x : B) (y : Set.range (· • (f.range : Set B) : B → Set B)) : +theorem g_apply_fromCoset (x : B) (y : X) : g x (fromCoset y) = fromCoset ⟨x • ↑y, by obtain ⟨z, hz⟩ := y.2; exact ⟨x * z, by simp [← hz, smul_smul]⟩⟩ := rfl diff --git a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean index 1a42f23763056..892709d29b993 100644 --- a/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean +++ b/Mathlib/Algebra/Category/Grp/EquivalenceGroupAddGroup.lean @@ -20,12 +20,6 @@ open CategoryTheory namespace Grp --- Porting note: Lean cannot find these now -private instance (X : Grp) : MulOneClass X.α := X.str.toMulOneClass -private instance (X : CommGrp) : MulOneClass X.α := X.str.toMulOneClass -private instance (X : AddGrp) : AddZeroClass X.α := X.str.toAddZeroClass -private instance (X : AddCommGrp) : AddZeroClass X.α := X.str.toAddZeroClass - /-- The functor `Grp ⥤ AddGrp` by sending `X ↦ Additive X` and `f ↦ f`. -/ @[simps] diff --git a/Mathlib/Algebra/Category/Grp/Injective.lean b/Mathlib/Algebra/Category/Grp/Injective.lean index f8ea96a6004ef..a5f8e576a886a 100644 --- a/Mathlib/Algebra/Category/Grp/Injective.lean +++ b/Mathlib/Algebra/Category/Grp/Injective.lean @@ -57,9 +57,9 @@ theorem Module.Baer.of_divisible [DivisibleBy A ℤ] : Module.Baer ℤ A := fun namespace AddCommGrp -theorem injective_as_module_iff : Injective (⟨A⟩ : ModuleCat ℤ) ↔ +theorem injective_as_module_iff : Injective (ModuleCat.of ℤ A) ↔ Injective (⟨A,inferInstance⟩ : AddCommGrp) := - ((forget₂ (ModuleCat ℤ) AddCommGrp).asEquivalence.map_injective_iff ⟨A⟩).symm + ((forget₂ (ModuleCat ℤ) AddCommGrp).asEquivalence.map_injective_iff (ModuleCat.of ℤ A)).symm instance injective_of_divisible [DivisibleBy A ℤ] : Injective (⟨A,inferInstance⟩ : AddCommGrp) := diff --git a/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean b/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean index 242349db0fa0c..cd88f753ea5b8 100644 --- a/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean +++ b/Mathlib/Algebra/Category/Grp/ZModuleEquivalence.lean @@ -29,12 +29,13 @@ instance forget₂_addCommGroup_full : (forget₂ (ModuleCat ℤ) AddCommGrp.{u} -- `AddMonoidHom.toIntLinearMap` doesn't work here because `A` and `B` are not -- definitionally equal to the canonical `AddCommGroup.toIntModule` module -- instances it expects. - f := ⟨@LinearMap.mk _ _ _ _ _ _ _ _ _ A.isModule B.isModule - { toFun := f, - map_add' := AddMonoidHom.map_add (show A.carrier →+ B.carrier from f) } - (fun n x => by - convert AddMonoidHom.map_zsmul (show A.carrier →+ B.carrier from f) x n <;> - ext <;> apply int_smul_eq_zsmul), rfl⟩ + f := ⟨@ModuleCat.ofHom _ _ _ _ _ A.isModule _ B.isModule <| + @LinearMap.mk _ _ _ _ _ _ _ _ _ A.isModule B.isModule + { toFun := f, + map_add' := AddMonoidHom.map_add (show A.carrier →+ B.carrier from f) } + (fun n x => by + convert AddMonoidHom.map_zsmul (show A.carrier →+ B.carrier from f) x n <;> + ext <;> apply int_smul_eq_zsmul), rfl⟩ /-- The forgetful functor from `ℤ` modules to `AddCommGrp` is essentially surjective. -/ instance forget₂_addCommGrp_essSurj : (forget₂ (ModuleCat ℤ) AddCommGrp.{u}).EssSurj where diff --git a/Mathlib/Algebra/Category/ModuleCat/Abelian.lean b/Mathlib/Algebra/Category/ModuleCat/Abelian.lean index fcb99e727a6c4..2bb2a6d564458 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Abelian.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Abelian.lean @@ -29,9 +29,9 @@ variable {R : Type u} [Ring R] {M N : ModuleCat.{v} R} (f : M ⟶ N) /-- In the category of modules, every monomorphism is normal. -/ def normalMono (hf : Mono f) : NormalMono f where - Z := of R (N ⧸ LinearMap.range f) - g := f.range.mkQ - w := LinearMap.range_mkQ_comp _ + Z := of R (N ⧸ LinearMap.range f.hom) + g := ofHom f.hom.range.mkQ + w := hom_ext <| LinearMap.range_mkQ_comp _ isLimit := /- The following [invalid Lean code](https://github.com/leanprover-community/lean/issues/341) might help you understand what's going on here: @@ -43,16 +43,16 @@ def normalMono (hf : Mono f) : NormalMono f where ``` -/ IsKernel.isoKernel _ _ (kernelIsLimit _) - (LinearEquiv.toModuleIso' + (LinearEquiv.toModuleIso ((Submodule.quotEquivOfEqBot _ (ker_eq_bot_of_mono _)).symm ≪≫ₗ - (LinearMap.quotKerEquivRange f ≪≫ₗ + (LinearMap.quotKerEquivRange f.hom ≪≫ₗ LinearEquiv.ofEq _ _ (Submodule.ker_mkQ _).symm))) <| by ext; rfl /-- In the category of modules, every epimorphism is normal. -/ def normalEpi (hf : Epi f) : NormalEpi f where - W := of R (LinearMap.ker f) - g := (LinearMap.ker f).subtype - w := LinearMap.comp_ker_subtype _ + W := of R (LinearMap.ker f.hom) + g := ofHom (LinearMap.ker f.hom).subtype + w := hom_ext <| LinearMap.comp_ker_subtype _ isColimit := /- The following invalid Lean code might help you understand what's going on here: ``` @@ -63,9 +63,9 @@ def normalEpi (hf : Epi f) : NormalEpi f where ``` -/ IsCokernel.cokernelIso _ _ (cokernelIsColimit _) - (LinearEquiv.toModuleIso' + (LinearEquiv.toModuleIso (Submodule.quotEquivOfEq _ _ (Submodule.range_subtype _) ≪≫ₗ - LinearMap.quotKerEquivRange f ≪≫ₗ + LinearMap.quotKerEquivRange f.hom ≪≫ₗ LinearEquiv.ofTop _ (range_eq_top_of_epi _))) <| by ext; rfl /-- The category of R-modules is abelian. -/ diff --git a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean index e23eebad47930..41760fe6fdefd 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Adjunctions.lean @@ -15,6 +15,8 @@ the forgetful functor from `R`-modules to types. -/ +assert_not_exists Cardinal + noncomputable section open CategoryTheory @@ -34,9 +36,9 @@ free `R`-module with generators `x : X`, implemented as the type `X →₀ R`. -/ def free : Type u ⥤ ModuleCat R where obj X := ModuleCat.of R (X →₀ R) - map {_ _} f := Finsupp.lmapDomain _ _ f - map_id := by intros; exact Finsupp.lmapDomain_id _ _ - map_comp := by intros; exact Finsupp.lmapDomain_comp _ _ _ _ + map {_ _} f := ofHom <| Finsupp.lmapDomain _ _ f + map_id := by intros; ext : 1; exact Finsupp.lmapDomain_id _ _ + map_comp := by intros; ext : 1; exact Finsupp.lmapDomain_comp _ _ _ _ variable {R} @@ -47,13 +49,13 @@ noncomputable def freeMk {X : Type u} (x : X) : (free R).obj X := Finsupp.single lemma free_hom_ext {X : Type u} {M : ModuleCat.{u} R} {f g : (free R).obj X ⟶ M} (h : ∀ (x : X), f (freeMk x) = g (freeMk x)) : f = g := - (Finsupp.lhom_ext' (fun x ↦ LinearMap.ext_ring (h x))) + ModuleCat.hom_ext (Finsupp.lhom_ext' (fun x ↦ LinearMap.ext_ring (h x))) /-- The morphism of modules `(free R).obj X ⟶ M` corresponding to a map `f : X ⟶ M`. -/ noncomputable def freeDesc {X : Type u} {M : ModuleCat.{u} R} (f : X ⟶ M) : (free R).obj X ⟶ M := - Finsupp.lift M R X f + ofHom <| Finsupp.lift M R X f @[simp] lemma freeDesc_apply {X : Type u} {M : ModuleCat.{u} R} (f : X ⟶ M) (x : X) : @@ -107,12 +109,11 @@ namespace FreeMonoidal (This should not be used directly: it is part of the implementation of the monoidal structure on the functor `free R`.) -/ def εIso : 𝟙_ (ModuleCat R) ≅ (free R).obj (𝟙_ (Type u)) where - hom := Finsupp.lsingle PUnit.unit - inv := Finsupp.lapply PUnit.unit + hom := ofHom <| Finsupp.lsingle PUnit.unit + inv := ofHom <| Finsupp.lapply PUnit.unit hom_inv_id := by - ext x - dsimp - erw [Finsupp.lapply_apply, Finsupp.lsingle_apply, Finsupp.single_eq_same] + ext + simp [free] inv_hom_id := by ext ⟨⟩ dsimp [freeMk] diff --git a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean index d2d388822bfff..275ae2fa12b4f 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Algebra.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Algebra.lean @@ -51,18 +51,9 @@ theorem isScalarTower_of_algebra_moduleCat (M : ModuleCat.{v} A) : IsScalarTower attribute [scoped instance] ModuleCat.isScalarTower_of_algebra_moduleCat -- We verify that the morphism spaces become `k`-modules. -example (M N : ModuleCat.{v} A) : Module k (M ⟶ N) := LinearMap.module --- Porting note: used to be `by infer_instance` instead of `LinearMap.module` +example (M N : ModuleCat.{v} A) : Module k (M ⟶ N) := inferInstance instance linearOverField : Linear k (ModuleCat.{v} A) where - -- Porting note: used to be `by infer_instance` instead of `LinearMap.module` - homModule _ _ := LinearMap.module - smul_comp := by - -- Porting note: this was automatic by `aesop_cat` - intros - ext - dsimp only [coe_comp, Function.comp_apply] - rw [LinearMap.smul_apply, LinearMap.map_smul_of_tower] - rfl + homModule _ _ := inferInstance end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Basic.lean index 417c5c7e12758..9d0fdd30373c1 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Basic.lean @@ -22,33 +22,15 @@ respectively. To construct an object in the category of `R`-modules from a type `M` with an instance of the `Module` typeclass, write `of R M`. There is a coercion in the other direction. +The roundtrip `↑(of R M)` is definitionally equal to `M` itself (when `M` is a type with `Module` +instance), and so is `of R ↑M` (when `M : ModuleCat R M`). -Similarly, there is a coercion from morphisms in `Module R` to linear maps. - -Porting note: the next two paragraphs should be revised. - -Unfortunately, Lean is not smart enough to see that, given an object `M : ModuleCat R`, -the expression `of R M`, where we coerce `M` to the carrier type, -is definitionally equal to `M` itself. -This means that to go the other direction, i.e., from linear maps/equivalences to (iso)morphisms -in the category of `R`-modules, we have to take care not to inadvertently end up with an -`of R M` where `M` is already an object. Hence, given `f : M →ₗ[R] N`, -* if `M N : ModuleCat R`, simply use `f`; -* if `M : ModuleCat R` and `N` is an unbundled `R`-module, use `↿f` or `asHomLeft f`; -* if `M` is an unbundled `R`-module and `N : ModuleCat R`, use `↾f` or `asHomRight f`; -* if `M` and `N` are unbundled `R`-modules, use `↟f` or `asHom f`. - -Similarly, given `f : M ≃ₗ[R] N`, use `toModuleIso`, `toModuleIso'Left`, `toModuleIso'Right` -or `toModuleIso'`, respectively. - -The arrow notations are localized, so you may have to `open ModuleCat` (or `open scoped ModuleCat`) -to use them. Note that the notation for `asHomLeft` clashes with the notation used to promote -functions between types to morphisms in the category `Type`, so to avoid confusion, it is probably a -good idea to avoid having the locales `ModuleCat` and `CategoryTheory.Type` open at the same time. - -If you get an error when trying to apply a theorem and the `convert` tactic produces goals of the -form `M = of R M`, then you probably used an incorrect variant of `asHom` or `toModuleIso`. +The morphisms are given their own type, not identified with `LinearMap`. +There is a cast from morphisms in `Module R` to linear maps, written `f.hom` (`ModuleCat.Hom.hom`). +To go from linear maps to morphisms in `Module R`, use `ModuleCat.ofHom`. +Similarly, given an isomorphism `f : M ≅ N` use `f.toLinearEquiv` and given a linear equiv +`f : M ≃ₗ[R] N`, use `f.toModuleIso`. -/ @@ -69,6 +51,7 @@ impose here that the `ℤ`-multiplication field from the module structure is def from the `isAddCommGroup` structure (contrary to what we do for all module structures in mathlib), which creates some difficulties down the road. -/ structure ModuleCat where + private mk :: /-- the underlying type of an object in `ModuleCat R` -/ carrier : Type v [isAddCommGroup : AddCommGroup carrier] @@ -88,27 +71,137 @@ instance : CoeSort (ModuleCat.{v} R) (Type v) := attribute [coe] ModuleCat.carrier +/-- The object in the category of R-algebras associated to a type equipped with the appropriate +typeclasses. This is the preferred way to construct a term of `ModuleCat R`. -/ +abbrev of (X : Type v) [AddCommGroup X] [Module R X] : ModuleCat.{v} R := + ⟨X⟩ + +lemma coe_of (X : Type v) [Ring X] [Module R X] : (of R X : Type v) = X := + rfl + +-- Ensure the roundtrips are reducibly defeq (so tactics like `rw` can see through them). +example (X : Type v) [Ring X] [Module R X] : (of R X : Type v) = X := by with_reducible rfl +example (M : ModuleCat.{v} R) : of R M = M := by with_reducible rfl + +variable {R} in +/-- The type of morphisms in `ModuleCat R`. -/ +@[ext] +structure Hom (M N : ModuleCat.{v} R) where + private mk :: + /-- The underlying linear map. -/ + hom : M →ₗ[R] N + instance moduleCategory : Category.{v, max (v+1) u} (ModuleCat.{v} R) where - Hom M N := M →ₗ[R] N - id _ := LinearMap.id - comp f g := g.comp f - id_comp _ := LinearMap.id_comp _ - comp_id _ := LinearMap.comp_id _ - assoc f g h := LinearMap.comp_assoc (f := f) (g := g) (h := h) + Hom M N := Hom M N + id _ := ⟨LinearMap.id⟩ + comp f g := ⟨g.hom.comp f.hom⟩ + +instance {M N : ModuleCat.{v} R} : CoeFun (M ⟶ N) (fun _ ↦ M → N) where + coe f := f.hom + +section + +variable {R} + +@[simp] +lemma hom_id {M : ModuleCat.{v} R} : (𝟙 M : M ⟶ M).hom = LinearMap.id := rfl + +/- Provided for rewriting. -/ +lemma id_apply (M : ModuleCat.{v} R) (x : M) : + (𝟙 M : M ⟶ M) x = x := by simp + +@[simp] +lemma hom_comp {M N O : ModuleCat.{v} R} (f : M ⟶ N) (g : N ⟶ O) : + (f ≫ g).hom = g.hom.comp f.hom := rfl + +/- Provided for rewriting. -/ +lemma comp_apply {M N O : ModuleCat.{v} R} (f : M ⟶ N) (g : N ⟶ O) (x : M) : + (f ≫ g) x = g (f x) := by simp + +@[ext] +lemma hom_ext {M N : ModuleCat.{v} R} {f g : M ⟶ N} (hf : f.hom = g.hom) : f = g := + Hom.ext hf + +lemma hom_bijective {M N : ModuleCat.{v} R} : + Function.Bijective (Hom.hom : (M ⟶ N) → (M →ₗ[R] N)) where + left f g h := by cases f; cases g; simpa using h + right f := ⟨⟨f⟩, rfl⟩ + +/-- Convenience shortcut for `ModuleCat.hom_bijective.injective`. -/ +lemma hom_injective {M N : ModuleCat.{v} R} : + Function.Injective (Hom.hom : (M ⟶ N) → (M →ₗ[R] N)) := + hom_bijective.injective + +/-- Convenience shortcut for `ModuleCat.hom_bijective.surjective`. -/ +lemma hom_surjective {M N : ModuleCat.{v} R} : + Function.Surjective (Hom.hom : (M ⟶ N) → (M →ₗ[R] N)) := + hom_bijective.surjective + +/-- Typecheck a `LinearMap` as a morphism in `ModuleCat R`. -/ +abbrev ofHom {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] + (f : X →ₗ[R] Y) : of R X ⟶ of R Y := + ⟨f⟩ + +@[deprecated (since := "2024-10-06")] alias asHom := ModuleCat.ofHom -instance {M N : ModuleCat.{v} R} : FunLike (M ⟶ N) M N := - LinearMap.instFunLike +/- Doesn't need to be `@[simp]` since the `simp` tactic applies this rewrite automatically: +`ofHom` and `hom` are reducibly equal to the constructor and projection respectively. -/ +lemma hom_ofHom {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] + [Module R Y] (f : X →ₗ[R] Y) : (ofHom f).hom = f := rfl -instance {M N : ModuleCat.{v} R} : LinearMapClass (M ⟶ N) R M N := - LinearMap.semilinearMapClass +@[simp] +lemma ofHom_hom {M N : ModuleCat.{v} R} (f : M ⟶ N) : + ofHom (Hom.hom f) = f := rfl + +@[simp] +lemma ofHom_id {M : Type v} [AddCommGroup M] [Module R M] : ofHom LinearMap.id = 𝟙 (of R M) := rfl + +@[simp] +lemma ofHom_comp {M N O : Type v} [AddCommGroup M] [AddCommGroup N] [AddCommGroup O] [Module R M] + [Module R N] [Module R O] (f : M →ₗ[R] N) (g : N →ₗ[R] O) : + ofHom (g.comp f) = ofHom f ≫ ofHom g := + rfl + +/- Doesn't need to be `@[simp]` since `simp only` can solve this. -/ +lemma ofHom_apply {M N : Type v} [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] + (f : M →ₗ[R] N) (x : M) : ofHom f x = f x := rfl + +@[simp] +lemma inv_hom_apply {M N : ModuleCat.{v} R} (e : M ≅ N) (x : M) : e.inv (e.hom x) = x := by + rw [← comp_apply] + simp + +@[simp] +lemma hom_inv_apply {M N : ModuleCat.{v} R} (e : M ≅ N) (x : N) : e.hom (e.inv x) = x := by + rw [← comp_apply] + simp + +/-- `ModuleCat.Hom.hom` bundled as an `Equiv`. -/ +def homEquiv {M N : ModuleCat.{v} R} : (M ⟶ N) ≃ (M →ₗ[R] N) where + toFun := Hom.hom + invFun := ofHom + left_inv _ := rfl + right_inv _ := rfl + +end + +instance : Inhabited (ModuleCat R) := + ⟨of R R⟩ instance moduleConcreteCategory : ConcreteCategory.{v} (ModuleCat.{v} R) where forget := { obj := fun R => R - map := fun f => f.toFun } - forget_faithful := ⟨fun h => LinearMap.ext (fun x => by - dsimp at h - rw [h])⟩ + map := fun f => f.hom } + forget_faithful := ⟨fun h => by ext x; simpa using congrFun h x⟩ + +/- Not a `@[simp]` lemma since it will rewrite the (co)domain of maps and cause +definitional equality issues. -/ +lemma forget_obj {M : ModuleCat.{v} R} : (forget (ModuleCat.{v} R)).obj M = M := rfl + +/- Not a `@[simp]` lemma since the LHS is a categorical arrow and the RHS is a plain function. -/ +lemma forget_map {M N : ModuleCat.{v} R} (f : M ⟶ N) : + (forget (ModuleCat.{v} R)).map f = f := + rfl -- Porting note: -- One might hope these two instances would not be needed, @@ -119,18 +212,10 @@ instance {M : ModuleCat.{v} R} : AddCommGroup ((forget (ModuleCat R)).obj M) := instance {M : ModuleCat.{v} R} : Module R ((forget (ModuleCat R)).obj M) := (inferInstance : Module R M) -@[ext] -lemma ext {M N : ModuleCat.{v} R} {f₁ f₂ : M ⟶ N} (h : ∀ (x : M), f₁ x = f₂ x) : f₁ = f₂ := - DFunLike.ext _ _ h - instance hasForgetToAddCommGroup : HasForget₂ (ModuleCat R) AddCommGrp where forget₂ := { obj := fun M => AddCommGrp.of M - map := fun f => AddCommGrp.ofHom f.toAddMonoidHom } - -/-- The object in the category of R-modules associated to an R-module -/ -def of (X : Type v) [AddCommGroup X] [Module R X] : ModuleCat R := - ⟨X⟩ + map := fun f => AddCommGrp.ofHom f.hom.toAddMonoidHom } @[simp] theorem forget₂_obj (X : ModuleCat R) : @@ -148,22 +233,14 @@ theorem forget₂_obj_moduleCat_of (X : Type v) [AddCommGroup X] [Module R X] : @[simp] theorem forget₂_map (X Y : ModuleCat R) (f : X ⟶ Y) : - (forget₂ (ModuleCat R) AddCommGrp).map f = LinearMap.toAddMonoidHom f := + (forget₂ (ModuleCat R) AddCommGrp).map f = f.hom.toAddMonoidHom := rfl instance : Inhabited (ModuleCat R) := ⟨of R PUnit⟩ -instance ofUnique {X : Type v} [AddCommGroup X] [Module R X] [i : Unique X] : Unique (of R X) := - i - @[simp] theorem of_coe (X : ModuleCat R) : of R X = X := rfl --- Porting note: the simpNF linter complains, but we really need this?! --- @[simp, nolint simpNF] -theorem coe_of (X : Type v) [AddCommGroup X] [Module R X] : (of R X : Type v) = X := - rfl - variable {R} /-- Forgetting to the underlying type and then building the bundled object returns the original @@ -174,33 +251,18 @@ def ofSelfIso (M : ModuleCat R) : ModuleCat.of R M ≅ M where inv := 𝟙 M theorem isZero_of_subsingleton (M : ModuleCat R) [Subsingleton M] : IsZero M where - unique_to X := ⟨⟨⟨(0 : M →ₗ[R] X)⟩, fun f => by + unique_to X := ⟨⟨⟨ofHom (0 : M →ₗ[R] X)⟩, fun f => by ext x rw [Subsingleton.elim x (0 : M)] dsimp simp⟩⟩ - unique_from X := ⟨⟨⟨(0 : X →ₗ[R] M)⟩, fun f => by + unique_from X := ⟨⟨⟨ofHom (0 : X →ₗ[R] M)⟩, fun f => by ext x subsingleton⟩⟩ instance : HasZeroObject (ModuleCat.{v} R) := ⟨⟨of R PUnit, isZero_of_subsingleton _⟩⟩ -variable {M N U : ModuleCat.{v} R} - -@[simp] -theorem id_apply (m : M) : (𝟙 M : M → M) m = m := - rfl - -@[simp] -theorem coe_comp (f : M ⟶ N) (g : N ⟶ U) : (f ≫ g : M → U) = g ∘ f := - rfl - -theorem comp_def (f : M ⟶ N) (g : N ⟶ U) : f ≫ g = g.comp f := - rfl - -@[simp] lemma forget_map (f : M ⟶ N) : (forget (ModuleCat R)).map f = (f : M → N) := rfl - end ModuleCat variable {R} @@ -208,37 +270,23 @@ variable {X₁ X₂ : Type v} open ModuleCat -/-- Reinterpreting a linear map in the category of `R`-modules. -/ -def ModuleCat.asHom [AddCommGroup X₁] [Module R X₁] [AddCommGroup X₂] [Module R X₂] : - (X₁ →ₗ[R] X₂) → (ModuleCat.of R X₁ ⟶ ModuleCat.of R X₂) := - id - -@[deprecated (since := "2024-10-06")] alias ModuleCat.ofHom := ModuleCat.asHom - /-- Reinterpreting a linear map in the category of `R`-modules -/ -scoped[ModuleCat] notation "↟" f:1024 => ModuleCat.asHom f +scoped[ModuleCat] notation "↟" f:1024 => ModuleCat.ofHom f -@[simp 1100] -theorem ModuleCat.asHom_apply {R : Type u} [Ring R] {X Y : Type v} [AddCommGroup X] [Module R X] - [AddCommGroup Y] [Module R Y] (f : X →ₗ[R] Y) (x : X) : (↟ f) x = f x := - rfl - -@[deprecated (since := "2024-10-06")] alias ModuleCat.ofHom_apply := ModuleCat.asHom_apply +@[deprecated (since := "2024-10-06")] alias ModuleCat.asHom_apply := ModuleCat.ofHom_apply -/-- Reinterpreting a linear map in the category of `R`-modules. -/ -def ModuleCat.asHomRight [AddCommGroup X₁] [Module R X₁] {X₂ : ModuleCat.{v} R} : - (X₁ →ₗ[R] X₂) → (ModuleCat.of R X₁ ⟶ X₂) := - id +-- Since `of` and the coercion now roundtrip reducibly, we don't need to distinguish in which place +-- we need to add `of` when coercing from linear maps to morphisms. +@[deprecated ModuleCat.ofHom (since := "2024-11-29")] alias ModuleCat.asHomRight := ModuleCat.ofHom +@[deprecated ModuleCat.ofHom (since := "2024-11-29")] alias ModuleCat.asHomLeft := ModuleCat.ofHom -/-- Reinterpreting a linear map in the category of `R`-modules. -/ +/-- Reinterpreting a linear map in the category of `R`-modules. +This notation is deprecated: use `↟` instead. +-/ scoped[ModuleCat] notation "↾" f:1024 => ModuleCat.asHomRight f - -/-- Reinterpreting a linear map in the category of `R`-modules. -/ -def ModuleCat.asHomLeft {X₁ : ModuleCat.{v} R} [AddCommGroup X₂] [Module R X₂] : - (X₁ →ₗ[R] X₂) → (X₁ ⟶ ModuleCat.of R X₂) := - id - -/-- Reinterpreting a linear map in the category of `R`-modules. -/ +/-- Reinterpreting a linear map in the category of `R`-modules. +This notation is deprecated: use `↟` instead. +-/ scoped[ModuleCat] notation "↿" f:1024 => ModuleCat.asHomLeft f section @@ -247,21 +295,24 @@ section @[simps] def LinearEquiv.toModuleIso {g₁ : AddCommGroup X₁} {g₂ : AddCommGroup X₂} {m₁ : Module R X₁} {m₂ : Module R X₂} (e : X₁ ≃ₗ[R] X₂) : ModuleCat.of R X₁ ≅ ModuleCat.of R X₂ where - hom := (e : X₁ →ₗ[R] X₂) - inv := (e.symm : X₂ →ₗ[R] X₁) + hom := ofHom (e : X₁ →ₗ[R] X₂) + inv := ofHom (e.symm : X₂ →ₗ[R] X₁) hom_inv_id := by ext; apply e.left_inv inv_hom_id := by ext; apply e.right_inv /-- Build an isomorphism in the category `Module R` from a `LinearEquiv` between `Module`s. -/ +@[deprecated LinearEquiv.toModuleIso (since := "2024-11-29")] abbrev LinearEquiv.toModuleIso' {M N : ModuleCat.{v} R} (i : M ≃ₗ[R] N) : M ≅ N := i.toModuleIso /-- Build an isomorphism in the category `ModuleCat R` from a `LinearEquiv` between `Module`s. -/ +@[deprecated LinearEquiv.toModuleIso (since := "2024-11-29")] abbrev LinearEquiv.toModuleIso'Left {X₁ : ModuleCat.{v} R} [AddCommGroup X₂] [Module R X₂] (e : X₁ ≃ₗ[R] X₂) : X₁ ≅ ModuleCat.of R X₂ := e.toModuleIso /-- Build an isomorphism in the category `ModuleCat R` from a `LinearEquiv` between `Module`s. -/ +@[deprecated LinearEquiv.toModuleIso (since := "2024-11-29")] abbrev LinearEquiv.toModuleIso'Right [AddCommGroup X₁] [Module R X₁] {X₂ : ModuleCat.{v} R} (e : X₁ ≃ₗ[R] X₂) : ModuleCat.of R X₁ ≅ X₂ := e.toModuleIso @@ -270,7 +321,7 @@ namespace CategoryTheory.Iso /-- Build a `LinearEquiv` from an isomorphism in the category `ModuleCat R`. -/ def toLinearEquiv {X Y : ModuleCat R} (i : X ≅ Y) : X ≃ₗ[R] Y := - LinearEquiv.ofLinear i.hom i.inv i.inv_hom_id i.hom_inv_id + LinearEquiv.ofLinear i.hom.hom i.inv.hom (by aesop) (by aesop) end CategoryTheory.Iso @@ -286,45 +337,122 @@ end namespace ModuleCat -instance {M N : ModuleCat.{v} R} : AddCommGroup (M ⟶ N) := LinearMap.addCommGroup +section AddCommGroup + +variable {M N : ModuleCat.{v} R} + +instance : Add (M ⟶ N) where + add f g := ⟨f.hom + g.hom⟩ + +@[simp] lemma hom_add (f g : M ⟶ N) : (f + g).hom = f.hom + g.hom := rfl + +instance : Zero (M ⟶ N) where + zero := ⟨0⟩ + +@[simp] lemma hom_zero : (0 : M ⟶ N).hom = 0 := rfl + +instance : SMul ℕ (M ⟶ N) where + smul n f := ⟨n • f.hom⟩ + +@[simp] lemma hom_nsmul (n : ℕ) (f : M ⟶ N) : (n • f).hom = n • f.hom := rfl + +instance : Neg (M ⟶ N) where + neg f := ⟨-f.hom⟩ + +@[simp] lemma hom_neg (f : M ⟶ N) : (-f).hom = -f.hom := rfl + +instance : Sub (M ⟶ N) where + sub f g := ⟨f.hom - g.hom⟩ + +@[simp] lemma hom_sub (f g : M ⟶ N) : (f - g).hom = f.hom - g.hom := rfl + +instance : SMul ℤ (M ⟶ N) where + smul n f := ⟨n • f.hom⟩ + +@[simp] lemma hom_zsmul (n : ℕ) (f : M ⟶ N) : (n • f).hom = n • f.hom := rfl + +instance : AddCommGroup (M ⟶ N) := + Function.Injective.addCommGroup (Hom.hom) hom_injective + rfl (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + +@[simp] lemma hom_sum {ι : Type*} (f : ι → (M ⟶ N)) (s : Finset ι) : + (∑ i in s, f i).hom = ∑ i in s, (f i).hom := + map_sum ({ toFun := ModuleCat.Hom.hom, map_zero' := ModuleCat.hom_zero, map_add' := hom_add } : + (M ⟶ N) →+ (M →ₗ[R] N)) _ _ instance : Preadditive (ModuleCat.{v} R) where - add_comp P Q R f f' g := by - ext - dsimp - erw [map_add] - rfl instance forget₂_addCommGrp_additive : (forget₂ (ModuleCat.{v} R) AddCommGrp).Additive where +/-- `ModuleCat.Hom.hom` bundled as an additive equivalence. -/ +@[simps!] +def homAddEquiv : (M ⟶ N) ≃+ (M →ₗ[R] N) := + { homEquiv with + map_add' := fun _ _ => rfl } + +end AddCommGroup + +section SMul + +variable {M N : ModuleCat.{v} R} {S : Type*} [Monoid S] [DistribMulAction S N] [SMulCommClass R S N] + +instance : SMul S (M ⟶ N) where + smul c f := ⟨c • f.hom⟩ + +@[simp] lemma hom_smul (s : S) (f : M ⟶ N) : (s • f).hom = s • f.hom := rfl + +end SMul + +section Module + +variable {M N : ModuleCat.{v} R} {S : Type*} [Semiring S] [Module S N] [SMulCommClass R S N] + +instance Hom.instModule : Module S (M ⟶ N) := + Function.Injective.module S + { toFun := Hom.hom, map_zero' := hom_zero, map_add' := hom_add } + hom_injective + (fun _ _ => rfl) + +/-- `ModuleCat.Hom.hom` bundled as a linear equivalence. -/ +@[simps] +def homLinearEquiv : (M ⟶ N) ≃ₗ[S] (M →ₗ[R] N) := + { homAddEquiv with + map_smul' := fun _ _ => rfl } + +end Module + section variable {S : Type u} [CommRing S] +variable {M N : ModuleCat.{v} S} + instance : Linear S (ModuleCat.{v} S) where - homModule _ _ := LinearMap.module - smul_comp := by - intros - ext - dsimp - rw [LinearMap.smul_apply, LinearMap.smul_apply, map_smul] - rfl variable {X Y X' Y' : ModuleCat.{v} S} theorem Iso.homCongr_eq_arrowCongr (i : X ≅ X') (j : Y ≅ Y') (f : X ⟶ Y) : - Iso.homCongr i j f = LinearEquiv.arrowCongr i.toLinearEquiv j.toLinearEquiv f := + Iso.homCongr i j f = ⟨LinearEquiv.arrowCongr i.toLinearEquiv j.toLinearEquiv f.hom⟩ := rfl theorem Iso.conj_eq_conj (i : X ≅ X') (f : End X) : - Iso.conj i f = LinearEquiv.conj i.toLinearEquiv f := + Iso.conj i f = ⟨LinearEquiv.conj i.toLinearEquiv f.hom⟩ := rfl end variable (M N : ModuleCat.{v} R) +/-- `ModuleCat.Hom.hom` as an isomorphism of monoids. -/ +@[simps] +def endMulEquiv : End M ≃* (M →ₗ[R] M) where + toFun := ModuleCat.Hom.hom + invFun := ModuleCat.ofHom + map_mul' _ _ := rfl + left_inv _ := rfl + right_inv _ := rfl + /-- The scalar multiplication on an object of `ModuleCat R` considered as a morphism of rings from `R` to the endomorphisms of the underlying abelian group. -/ def smul : R →+* End ((forget₂ (ModuleCat R) AddCommGrp).obj M) where @@ -341,7 +469,7 @@ lemma smul_naturality {M N : ModuleCat.{v} R} (f : M ⟶ N) (r : R) : (forget₂ (ModuleCat R) AddCommGrp).map f ≫ N.smul r = M.smul r ≫ (forget₂ (ModuleCat R) AddCommGrp).map f := by ext x - exact (f.map_smul r x).symm + exact (f.hom.map_smul r x).symm variable (R) @@ -409,9 +537,9 @@ a morphism between the underlying objects in `AddCommGrp` and the compatibility with the scalar multiplication. -/ @[simps] def homMk : M ⟶ N where - toFun := φ - map_add' _ _ := φ.map_add _ _ - map_smul' r x := (congr_hom (hφ r) x).symm + hom.toFun := φ + hom.map_add' _ _ := φ.map_add _ _ + hom.map_smul' r x := (congr_hom (hφ r) x).symm lemma forget₂_map_homMk : (forget₂ (ModuleCat R) AddCommGrp).map (homMk φ hφ) = φ := rfl @@ -420,7 +548,7 @@ end instance : (forget (ModuleCat.{v} R)).ReflectsIsomorphisms where reflects f _ := - (inferInstance : IsIso ((LinearEquiv.mk f + (inferInstance : IsIso ((LinearEquiv.mk f.hom (asIso ((forget (ModuleCat R)).map f)).toEquiv.invFun (Equiv.left_inv _) (Equiv.right_inv _)).toModuleIso).hom) @@ -433,15 +561,45 @@ instance : (forget₂ (ModuleCat.{v} R) AddCommGrp.{v}).ReflectsIsomorphisms whe end ModuleCat +section Bilinear + +variable {R : Type*} [CommRing R] + +namespace ModuleCat + +/-- Turn a bilinear map into a homomorphism. -/ +@[simps] +def ofHom₂ {M N P : ModuleCat.{u} R} (f : M →ₗ[R] N →ₗ[R] P) : + M ⟶ of R (N ⟶ P) := + ofHom <| homLinearEquiv.symm.toLinearMap ∘ₗ f + +/-- Turn a homomorphism into a bilinear map. -/ +@[simps!] +def Hom.hom₂ {M N P : ModuleCat.{u} R} + -- We write `Hom` instead of `M ⟶ (of R (N ⟶ P))`, otherwise dot notation breaks + -- since it is expecting the type of `f` to be `ModuleCat.Hom`, not `Quiver.Hom`. + (f : Hom M (of R (N ⟶ P))) : + M →ₗ[R] N →ₗ[R] P := + Hom.hom (by convert (f ≫ ofHom homLinearEquiv.toLinearMap)) + +@[simp] lemma Hom.hom₂_ofHom₂ {M N P : ModuleCat.{u} R} (f : M →ₗ[R] N →ₗ[R] P) : + (ofHom₂ f).hom₂ = f := rfl + +@[simp] lemma ofHom₂_hom₂ {M N P : ModuleCat.{u} R} (f : M ⟶ of R (N ⟶ P)) : + ofHom₂ f.hom₂ = f := rfl + +end ModuleCat + +end Bilinear + /-! `@[simp]` lemmas for `LinearMap.comp` and categorical identities. -/ @[simp] theorem LinearMap.comp_id_moduleCat {R} [Ring R] {G : ModuleCat.{u} R} {H : Type u} [AddCommGroup H] [Module R H] (f : G →ₗ[R] H) : - f.comp (𝟙 G) = f := - Category.id_comp (ModuleCat.asHom f) + f.comp (𝟙 G : G ⟶ G).hom = f := by simp + @[simp] theorem LinearMap.id_moduleCat_comp {R} [Ring R] {G : Type u} [AddCommGroup G] [Module R G] {H : ModuleCat.{u} R} (f : G →ₗ[R] H) : - LinearMap.comp (𝟙 H) f = f := - Category.comp_id (ModuleCat.asHom f) + LinearMap.comp (𝟙 H : H ⟶ H).hom f = f := by simp diff --git a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean index b1862b543607c..4387064834c7e 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Biproducts.lean @@ -41,10 +41,12 @@ def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) π := { app := fun j => Discrete.casesOn j fun j => - WalkingPair.casesOn j (LinearMap.fst R M N) (LinearMap.snd R M N) + WalkingPair.casesOn j (ofHom <| LinearMap.fst R M N) (ofHom <| LinearMap.snd R M N) naturality := by rintro ⟨⟨⟩⟩ ⟨⟨⟩⟩ ⟨⟨⟨⟩⟩⟩ <;> rfl } } isLimit := - { lift := fun s => LinearMap.prod (s.π.app ⟨WalkingPair.left⟩) (s.π.app ⟨WalkingPair.right⟩) + { lift := fun s => ofHom <| LinearMap.prod + (s.π.app ⟨WalkingPair.left⟩).hom + (s.π.app ⟨WalkingPair.right⟩).hom fac := by rintro s (⟨⟩ | ⟨⟩) <;> rfl uniq := fun s m w => by simp_rw [← w ⟨WalkingPair.left⟩, ← w ⟨WalkingPair.right⟩] @@ -52,12 +54,12 @@ def binaryProductLimitCone (M N : ModuleCat.{v} R) : Limits.LimitCone (pair M N) @[simp] theorem binaryProductLimitCone_cone_π_app_left (M N : ModuleCat.{v} R) : - (binaryProductLimitCone M N).cone.π.app ⟨WalkingPair.left⟩ = LinearMap.fst R M N := + (binaryProductLimitCone M N).cone.π.app ⟨WalkingPair.left⟩ = ofHom (LinearMap.fst R M N) := rfl @[simp] theorem binaryProductLimitCone_cone_π_app_right (M N : ModuleCat.{v} R) : - (binaryProductLimitCone M N).cone.π.app ⟨WalkingPair.right⟩ = LinearMap.snd R M N := + (binaryProductLimitCone M N).cone.π.app ⟨WalkingPair.right⟩ = ofHom (LinearMap.snd R M N) := rfl /-- We verify that the biproduct in `ModuleCat R` is isomorphic to @@ -69,12 +71,12 @@ noncomputable def biprodIsoProd (M N : ModuleCat.{v} R) : @[simp, elementwise] theorem biprodIsoProd_inv_comp_fst (M N : ModuleCat.{v} R) : - (biprodIsoProd M N).inv ≫ biprod.fst = LinearMap.fst R M N := + (biprodIsoProd M N).inv ≫ biprod.fst = ofHom (LinearMap.fst R M N) := IsLimit.conePointUniqueUpToIso_inv_comp _ _ (Discrete.mk WalkingPair.left) @[simp, elementwise] theorem biprodIsoProd_inv_comp_snd (M N : ModuleCat.{v} R) : - (biprodIsoProd M N).inv ≫ biprod.snd = LinearMap.snd R M N := + (biprodIsoProd M N).inv ≫ biprod.snd = ofHom (LinearMap.snd R M N) := IsLimit.conePointUniqueUpToIso_inv_comp _ _ (Discrete.mk WalkingPair.right) namespace HasLimit @@ -85,14 +87,15 @@ variable {J : Type w} (f : J → ModuleCat.{max w v} R) to the cartesian product of those groups. -/ @[simps] -def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where - toFun x j := s.π.app ⟨j⟩ x - map_add' x y := by - simp only [Functor.const_obj_obj, map_add] - rfl - map_smul' r x := by - simp only [Functor.const_obj_obj, map_smul] - rfl +def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) := + ofHom + { toFun := fun x j => s.π.app ⟨j⟩ x + map_add' := fun x y => by + simp only [Functor.const_obj_obj, map_add] + rfl + map_smul' := fun r x => by + simp only [Functor.const_obj_obj, map_smul] + rfl } /-- Construct limit data for a product in `ModuleCat R`, using `ModuleCat.of R (∀ j, F.obj j)`. -/ @@ -100,13 +103,12 @@ def lift (s : Fan f) : s.pt ⟶ ModuleCat.of R (∀ j, f j) where def productLimitCone : Limits.LimitCone (Discrete.functor f) where cone := { pt := ModuleCat.of R (∀ j, f j) - π := Discrete.natTrans fun j => (LinearMap.proj j.as : (∀ j, f j) →ₗ[R] f j.as) } + π := Discrete.natTrans fun j => ofHom (LinearMap.proj j.as : (∀ j, f j) →ₗ[R] f j.as) } isLimit := { lift := lift.{_, v} f fac := fun _ _ => rfl uniq := fun s m w => by - ext x - funext j + ext x j exact congr_arg (fun g : s.pt ⟶ f j => (g : s.pt → f j) x) (w ⟨j⟩) } end HasLimit @@ -124,7 +126,7 @@ noncomputable def biproductIsoPi [Finite J] (f : J → ModuleCat.{v} R) : @[simp, elementwise] theorem biproductIsoPi_inv_comp_π [Finite J] (f : J → ModuleCat.{v} R) (j : J) : - (biproductIsoPi f).inv ≫ biproduct.π f j = (LinearMap.proj j : (∀ j, f j) →ₗ[R] f j) := + (biproductIsoPi f).inv ≫ biproduct.π f j = ofHom (LinearMap.proj j : (∀ j, f j) →ₗ[R] f j) := IsLimit.conePointUniqueUpToIso_inv_comp _ _ (Discrete.mk j) end ModuleCat @@ -144,8 +146,8 @@ 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 := ((ShortComplex.Splitting.ofExactOfSection _ - (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.asHom j) - (ModuleCat.asHom g) exac) (asHom f) h + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.ofHom j) + (ModuleCat.ofHom g) exac) (ofHom f) (hom_ext h) (by simpa only [ModuleCat.mono_iff_injective])).isoBinaryBiproduct ≪≫ biprodIsoProd _ _ ).symm.toLinearEquiv @@ -154,8 +156,8 @@ 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 := ((ShortComplex.Splitting.ofExactOfRetraction _ - (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.asHom j) - (ModuleCat.asHom g) exac) (ModuleCat.asHom f) h + (ShortComplex.Exact.moduleCat_of_range_eq_ker (ModuleCat.ofHom j) + (ModuleCat.ofHom g) exac) (ModuleCat.ofHom f) (hom_ext h) (by simpa only [ModuleCat.epi_iff_surjective] using hg)).isoBinaryBiproduct ≪≫ biprodIsoProd _ _).symm.toLinearEquiv diff --git a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean index 4bbcee39a959e..f1d6988e3fced 100644 --- a/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/ChangeOfRings.lean @@ -56,15 +56,18 @@ variable (M : ModuleCat.{v} S) /-- Any `S`-module M is also an `R`-module via a ring homomorphism `f : R ⟶ S` by defining `r • m := f r • m` (`Module.compHom`). This is called restriction of scalars. -/ -def obj' : ModuleCat R where - carrier := M - isModule := Module.compHom M f +def obj' : ModuleCat R := + let _ := Module.compHom M f + of R M /-- Given an `S`-linear map `g : M → M'` between `S`-modules, `g` is also `R`-linear between `M` and `M'` by means of restriction of scalars. -/ def map' {M M' : ModuleCat.{v} S} (g : M ⟶ M') : obj' f M ⟶ obj' f M' := - { g with map_smul' := fun r => g.map_smul (f r) } + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(X := ...)` and `(Y := ...)`. + -- This suggests `RestrictScalars.obj'` needs to be redesigned. + ofHom (X := obj' f M) (Y := obj' f M') + { g.hom with map_smul' := fun r => g.hom.map_smul (f r) } end RestrictScalars @@ -76,24 +79,21 @@ def restrictScalars {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R → ModuleCat.{v} S ⥤ ModuleCat.{v} R where obj := RestrictScalars.obj' f map := RestrictScalars.map' f - map_id _ := LinearMap.ext fun _ => rfl - map_comp _ _ := LinearMap.ext fun _ => rfl instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) : (restrictScalars.{v} f).Faithful where - map_injective h := - LinearMap.ext fun x => by simpa only using DFunLike.congr_fun h x + map_injective h := by + ext x + simpa only using DFunLike.congr_fun (ModuleCat.hom_ext_iff.mp h) x instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) : (restrictScalars.{v} f).PreservesMonomorphisms where preserves _ h := by rwa [mono_iff_injective] at h ⊢ -- Porting note: this should be automatic -instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] {f : R →+* S} - {M : ModuleCat.{v} S} : Module R <| (restrictScalars f).obj M := - inferInstanceAs <| Module R <| RestrictScalars.obj' f M - --- Porting note: this should be automatic +-- TODO: this instance gives diamonds if `f : S →+* S`, see `PresheafOfModules.pushforward₀`. +-- The correct solution is probably to define explicit maps between `M` and +-- `(restrictScalars f).obj M`. instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] {f : R →+* S} {M : ModuleCat.{v} S} : Module S <| (restrictScalars f).obj M := inferInstanceAs <| Module S M @@ -105,20 +105,18 @@ theorem restrictScalars.map_apply {R : Type u₁} {S : Type u₂} [Ring R] [Ring @[simp] theorem restrictScalars.smul_def {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) - {M : ModuleCat.{v} S} (r : R) (m : (restrictScalars f).obj M) : r • m = (f r • m : M) := + {M : ModuleCat.{v} S} (r : R) (m : (restrictScalars f).obj M) : r • m = f r • show M from m := rfl theorem restrictScalars.smul_def' {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) {M : ModuleCat.{v} S} (r : R) (m : M) : - -- Porting note: clumsy way to coerce - let m' : (restrictScalars f).obj M := m - (r • m' : (restrictScalars f).obj M) = (f r • m : M) := + r • (show (restrictScalars f).obj M from m) = f r • m := rfl instance (priority := 100) sMulCommClass_mk {R : Type u₁} {S : Type u₂} [Ring R] [CommRing S] (f : R →+* S) (M : Type v) [I : AddCommGroup M] [Module S M] : - haveI : SMul R M := (RestrictScalars.obj' f (ModuleCat.mk M)).isModule.toSMul + haveI : SMul R M := (RestrictScalars.obj' f (ModuleCat.of S 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) @@ -129,14 +127,16 @@ morphisms `M ⟶ (ModuleCat.restrictScalars f).obj N`. -/ def semilinearMapAddEquiv {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) (M : ModuleCat.{v} R) (N : ModuleCat.{v} S) : (M →ₛₗ[f] N) ≃+ (M ⟶ (ModuleCat.restrictScalars f).obj N) where - toFun g := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + toFun g := ofHom (Y := (ModuleCat.restrictScalars f).obj N) <| { toFun := g map_add' := by simp map_smul' := by simp } invFun g := { toFun := g map_add' := by simp - map_smul' := g.map_smul } + map_smul' := g.hom.map_smul } left_inv _ := rfl right_inv _ := rfl map_add' _ _ := rfl @@ -149,7 +149,7 @@ variable {R : Type u₁} [Ring R] (f : R →+* R) to `M`. -/ def restrictScalarsId'App (hf : f = RingHom.id R) (M : ModuleCat R) : (restrictScalars f).obj M ≅ M := - LinearEquiv.toModuleIso' <| + LinearEquiv.toModuleIso <| @AddEquiv.toLinearEquiv _ _ _ _ _ _ (((restrictScalars f).obj M).isModule) _ (by rfl) (fun r x ↦ by subst hf; rfl) @@ -198,7 +198,11 @@ variable {R₁ : Type u₁} {R₂ : Type u₂} {R₃ : Type u₃} [Ring R₁] [R identifies to successively restricting scalars. -/ def restrictScalarsComp'App (hgf : gf = g.comp f) (M : ModuleCat R₃) : (restrictScalars gf).obj M ≅ (restrictScalars f).obj ((restrictScalars g).obj M) := - (AddEquiv.toLinearEquiv (by rfl) (fun r x ↦ by subst hgf; rfl)).toModuleIso' + (AddEquiv.toLinearEquiv + (M := ↑((restrictScalars gf).obj M)) + (M₂ := ↑((restrictScalars f).obj ((restrictScalars g).obj M))) + (by rfl) + (fun r x ↦ by subst hgf; rfl)).toModuleIso variable (hgf : gf = g.comp f) @@ -243,10 +247,14 @@ def restrictScalarsEquivalenceOfRingEquiv {R S} [Ring R] [Ring S] (e : R ≃+* S ModuleCat S ≌ ModuleCat R where functor := ModuleCat.restrictScalars e.toRingHom inverse := ModuleCat.restrictScalars e.symm - unitIso := NatIso.ofComponents (fun M ↦ LinearEquiv.toModuleIso' + unitIso := NatIso.ofComponents (fun M ↦ LinearEquiv.toModuleIso + (X₁ := M) + (X₂ := (restrictScalars e.symm.toRingHom).obj ((restrictScalars e.toRingHom).obj M)) { __ := AddEquiv.refl M map_smul' := fun s m ↦ congr_arg (· • m) (e.right_inv s).symm }) (by intros; rfl) - counitIso := NatIso.ofComponents (fun M ↦ LinearEquiv.toModuleIso' + counitIso := NatIso.ofComponents (fun M ↦ LinearEquiv.toModuleIso + (X₁ := (restrictScalars e.toRingHom).obj ((restrictScalars e.symm.toRingHom).obj M)) + (X₂ := M) { __ := AddEquiv.refl M map_smul' := fun r _ ↦ congr_arg (· • (_ : M)) (e.left_inv r)}) (by intros; rfl) functor_unitIso_comp := by intros; rfl @@ -279,33 +287,26 @@ variable (M : ModuleCat.{v} R) /-- Extension of scalars turn an `R`-module into `S`-module by M ↦ S ⨂ M -/ def obj' : ModuleCat S := - ⟨TensorProduct R ((restrictScalars f).obj ⟨S⟩) M⟩ + of _ (TensorProduct R ((restrictScalars f).obj (of _ S)) M) /-- Extension of scalars is a functor where an `R`-module `M` is sent to `S ⊗ M` and `l : M1 ⟶ M2` is sent to `s ⊗ m ↦ s ⊗ l m` -/ def map' {M1 M2 : ModuleCat.{v} R} (l : M1 ⟶ M2) : obj' f M1 ⟶ obj' f M2 := - by-- The "by apply" part makes this require 75% fewer heartbeats to process (https://github.com/leanprover-community/mathlib4/pull/16371). - apply @LinearMap.baseChange R S M1 M2 _ _ ((algebraMap S _).comp f).toAlgebra _ _ _ _ l - -theorem map'_id {M : ModuleCat.{v} R} : map' f (𝟙 M) = 𝟙 _ := - LinearMap.ext fun x : obj' f M => by - dsimp only [map'] - rw [ModuleCat.id_apply] -- Porting note: this got put in the dsimp by mathport - induction x using TensorProduct.induction_on with - | zero => rw [map_zero] - | tmul => -- Porting note: issues with synthesizing Algebra R S - erw [@LinearMap.baseChange_tmul R S M M _ _ (_), ModuleCat.id_apply] - | add _ _ ihx ihy => rw [map_add, ihx, ihy] + ofHom (@LinearMap.baseChange R S M1 M2 _ _ ((algebraMap S _).comp f).toAlgebra _ _ _ _ l.hom) + +theorem map'_id {M : ModuleCat.{v} R} : map' f (𝟙 M) = 𝟙 _ := by + ext x + simp [map'] theorem map'_comp {M₁ M₂ M₃ : ModuleCat.{v} R} (l₁₂ : M₁ ⟶ M₂) (l₂₃ : M₂ ⟶ M₃) : - map' f (l₁₂ ≫ l₂₃) = map' f l₁₂ ≫ map' f l₂₃ := - LinearMap.ext fun x : obj' f M₁ => by - dsimp only [map'] - induction x using TensorProduct.induction_on with - | zero => rfl - | tmul => rfl - | add _ _ ihx ihy => rw [map_add, map_add, ihx, ihy] + map' f (l₁₂ ≫ l₂₃) = map' f l₁₂ ≫ map' f l₂₃ := by + ext x + dsimp only [map'] + induction x using TensorProduct.induction_on with + | zero => rfl + | tmul => rfl + | add _ _ ihx ihy => rw [map_add, map_add, ihx, ihy] end ExtendScalars @@ -352,7 +353,7 @@ variable (M : Type v) [AddCommMonoid M] [Module R M] /-- Given an `R`-module M, consider Hom(S, M) -- the `R`-linear maps between S (as an `R`-module by means of restriction of scalars) and M. `S` acts on Hom(S, M) by `s • g = x ↦ g (x • s)` -/ -instance hasSMul : SMul S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M where +instance hasSMul : SMul S <| (restrictScalars f).obj (of _ S) →ₗ[R] M where smul s g := { toFun := fun s' : S => g (s' * s : S) map_add' := fun x y : S => by dsimp; rw [add_mul, map_add] @@ -363,16 +364,16 @@ instance hasSMul : SMul S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M where erw [smul_eq_mul, smul_eq_mul, mul_assoc] } @[simp] -theorem smul_apply' (s : S) (g : (restrictScalars f).obj ⟨S⟩ →ₗ[R] M) (s' : S) : +theorem smul_apply' (s : S) (g : (restrictScalars f).obj (of _ S) →ₗ[R] M) (s' : S) : (s • g) s' = g (s' * s : S) := rfl -instance mulAction : MulAction S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M := +instance mulAction : MulAction S <| (restrictScalars f).obj (of _ S) →ₗ[R] M := { CoextendScalars.hasSMul f _ with one_smul := fun g => LinearMap.ext fun s : S => by simp mul_smul := fun (s t : S) g => LinearMap.ext fun x : S => by simp [mul_assoc] } -instance distribMulAction : DistribMulAction S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M := +instance distribMulAction : DistribMulAction S <| (restrictScalars f).obj (of _ S) →ₗ[R] M := { CoextendScalars.mulAction f _ with smul_add := fun s g h => LinearMap.ext fun _ : S => by simp smul_zero := fun _ => LinearMap.ext fun _ : S => by simp } @@ -380,7 +381,7 @@ instance distribMulAction : DistribMulAction S <| (restrictScalars f).obj ⟨S /-- `S` acts on Hom(S, M) by `s • g = x ↦ g (x • s)`, this action defines an `S`-module structure on Hom(S, M). -/ -instance isModule : Module S <| (restrictScalars f).obj ⟨S⟩ →ₗ[R] M := +instance isModule : Module S <| (restrictScalars f).obj (of _ S) →ₗ[R] M := { CoextendScalars.distribMulAction f _ with add_smul := fun s1 s2 g => LinearMap.ext fun x : S => by simp [mul_add, LinearMap.map_add] zero_smul := fun g => LinearMap.ext fun x : S => by simp [LinearMap.map_zero] } @@ -392,18 +393,19 @@ variable (M : ModuleCat.{v} R) /-- If `M` is an `R`-module, then the set of `R`-linear maps `S →ₗ[R] M` is an `S`-module with scalar multiplication defined by `s • l := x ↦ l (x • s)`-/ def obj' : ModuleCat S := - ⟨(restrictScalars f).obj ⟨S⟩ →ₗ[R] M⟩ + of _ ((restrictScalars f).obj (of _ S) →ₗ[R] M) -instance : CoeFun (obj' f M) fun _ => S → M where coe g := g.toFun +instance : CoeFun (obj' f M) fun _ => S → M := + inferInstanceAs <| CoeFun ((restrictScalars f).obj (of _ S) →ₗ[R] M) _ /-- If `M, M'` are `R`-modules, then any `R`-linear map `g : M ⟶ M'` induces an `S`-linear map `(S →ₗ[R] M) ⟶ (S →ₗ[R] M')` defined by `h ↦ g ∘ h`-/ @[simps] -def map' {M M' : ModuleCat R} (g : M ⟶ M') : obj' f M ⟶ obj' f M' where - toFun h := g.comp h - map_add' _ _ := LinearMap.comp_add _ _ _ - map_smul' s h := LinearMap.ext fun t : S => by dsimp; rw [smul_apply',smul_apply']; simp - -- Porting note: smul_apply' not working in simp +def map' {M M' : ModuleCat R} (g : M ⟶ M') : obj' f M ⟶ obj' f M' := + ofHom + { toFun := fun h => g.hom.comp h + map_add' := fun _ _ => LinearMap.comp_add _ _ _ + map_smul' := fun s h => by ext; simp } end CoextendScalars @@ -416,14 +418,13 @@ def coextendScalars {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R → ModuleCat R ⥤ ModuleCat S where obj := CoextendScalars.obj' f map := CoextendScalars.map' f - map_id _ := LinearMap.ext fun _ => LinearMap.ext fun _ => rfl - map_comp _ _ := LinearMap.ext fun _ => LinearMap.ext fun _ => rfl + map_id _ := by ext; rfl + map_comp _ _ := by ext; rfl namespace CoextendScalars variable {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) --- Porting note: this coercion doesn't line up well with task below instance (M : ModuleCat R) : CoeFun ((coextendScalars f).obj M) fun _ => S → M := inferInstanceAs <| CoeFun (CoextendScalars.obj' f M) _ @@ -445,51 +446,50 @@ variable {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) /-- Given `R`-module X and `S`-module Y, any `g : (restrictScalars f).obj Y ⟶ X` corresponds to `Y ⟶ (coextendScalars f).obj X` by sending `y ↦ (s ↦ g (s • y))` -/ -@[simps apply_apply] def HomEquiv.fromRestriction {X : ModuleCat R} {Y : ModuleCat S} - (g : (restrictScalars f).obj Y ⟶ X) : Y ⟶ (coextendScalars f).obj X where - toFun := fun y : Y => - { toFun := fun s : S => g <| (s • y : Y) - map_add' := fun s1 s2 : S => by simp only [add_smul]; rw [LinearMap.map_add] - map_smul' := fun r (s : S) => by - -- Porting note: dsimp clears out some rw's but less eager to apply others with Lean 4 - dsimp - rw [← g.map_smul] - erw [smul_eq_mul, mul_smul] - rfl} - map_add' := fun y1 y2 : Y => - LinearMap.ext fun s : S => by - -- Porting note: double dsimp seems odd - dsimp only [id_eq, eq_mpr_eq_cast, AddHom.toFun_eq_coe, AddHom.coe_mk, RingHom.id_apply, - RingHom.toMonoidHom_eq_coe, OneHom.toFun_eq_coe, - MonoidHom.toOneHom_coe, MonoidHom.coe_coe, ZeroHom.coe_mk, smul_eq_mul, cast_eq, - LinearMap.coe_mk] - rw [LinearMap.add_apply, LinearMap.coe_mk, LinearMap.coe_mk] - dsimp only [AddHom.coe_mk] - rw [smul_add, map_add] - map_smul' := fun (s : S) (y : Y) => LinearMap.ext fun t : S => by - -- Porting note: used to be simp [mul_smul] - simp only [LinearMap.coe_mk, AddHom.coe_mk, RingHom.id_apply] - rw [ModuleCat.CoextendScalars.smul_apply', LinearMap.coe_mk] - dsimp - rw [mul_smul] + (g : (restrictScalars f).obj Y ⟶ X) : Y ⟶ (coextendScalars f).obj X := + ofHom + { toFun := fun y : Y => + { toFun := fun s : S => g <| (s • y : Y) + map_add' := fun s1 s2 : S => by simp only [add_smul]; rw [LinearMap.map_add] + map_smul' := fun r (s : S) => by + -- Porting note: dsimp clears out some rw's but less eager to apply others with Lean 4 + dsimp + rw [← g.hom.map_smul] + erw [smul_eq_mul, mul_smul] + rfl } + map_add' := fun y1 y2 : Y => + LinearMap.ext fun s : S => by + simp [smul_add, map_add] + map_smul' := fun (s : S) (y : Y) => LinearMap.ext fun t : S => by + simp [mul_smul] } + +/-- This should be autogenerated by `@[simps]` but we need to give `s` the correct type here. -/ +@[simp] lemma HomEquiv.fromRestriction_hom_apply_apply {X : ModuleCat R} {Y : ModuleCat S} + (g : (restrictScalars f).obj Y ⟶ X) (y) (s : S) : + (HomEquiv.fromRestriction f g).hom y s = g (s • y) := rfl /-- Given `R`-module X and `S`-module Y, any `g : Y ⟶ (coextendScalars f).obj X` corresponds to `(restrictScalars f).obj Y ⟶ X` by `y ↦ g y 1` -/ -@[simps apply] def HomEquiv.toRestriction {X Y} (g : Y ⟶ (coextendScalars f).obj X) : - (restrictScalars f).obj Y ⟶ X where - toFun := fun y : Y => (g y) (1 : S) - map_add' x y := by dsimp; rw [g.map_add, LinearMap.add_apply] - map_smul' r (y : Y) := by - dsimp - rw [← LinearMap.map_smul] - erw [smul_eq_mul, mul_one, LinearMap.map_smul] - -- Porting note: should probably change CoeFun for obj above - rw [← LinearMap.coe_toAddHom, ← AddHom.toFun_eq_coe] - rw [CoextendScalars.smul_apply (s := f r) (g := g y) (s' := 1), one_mul] - simp + (restrictScalars f).obj Y ⟶ X := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(X := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + ofHom (X := (restrictScalars f).obj Y) + { toFun := fun y : Y => (g y) (1 : S) + map_add' := fun x y => by dsimp; rw [g.hom.map_add, LinearMap.add_apply] + map_smul' := fun r (y : Y) => by + dsimp + rw [← LinearMap.map_smul] + erw [smul_eq_mul, mul_one, LinearMap.map_smul] + rw [CoextendScalars.smul_apply (s := f r) (g := g y) (s' := 1), one_mul] + simp } + +/-- This should be autogenerated by `@[simps]` but we need to give `1` the correct type here. -/ +@[simp] lemma HomEquiv.toRestriction_hom_apply {X : ModuleCat R} {Y : ModuleCat S} + (g : Y ⟶ (coextendScalars f).obj X) (y) : + (HomEquiv.toRestriction f g).hom y = g.hom y (1 : S) := rfl -- Porting note: add to address timeout in unit' /-- Auxiliary definition for `unit'` -/ @@ -521,17 +521,14 @@ def app' (Y : ModuleCat S) : Y →ₗ[S] (restrictScalars f ⋙ coextendScalars The natural transformation from identity functor to the composition of restriction and coextension of scalars. -/ --- @[simps] Porting note: not in normal form and not used +@[simps] protected def unit' : 𝟭 (ModuleCat S) ⟶ restrictScalars f ⋙ coextendScalars f where - app Y := app' f Y + app Y := ofHom (app' f Y) naturality Y Y' g := - LinearMap.ext fun y : Y => LinearMap.ext fun s : S => by + hom_ext <| LinearMap.ext fun y : Y => LinearMap.ext fun s : S => by -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10745): previously simp [CoextendScalars.map_apply] - simp only [ModuleCat.coe_comp, Functor.id_map, Functor.id_obj, Functor.comp_obj, - Functor.comp_map] - rw [coe_comp, coe_comp, Function.comp, Function.comp] - conv_rhs => rw [← LinearMap.coe_toAddHom, ← AddHom.toFun_eq_coe] - rw [CoextendScalars.map_apply, AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, + simp only [ModuleCat.hom_comp, Functor.id_map, Functor.id_obj, Functor.comp_obj, + Functor.comp_map, LinearMap.coe_comp, Function.comp, CoextendScalars.map_apply, restrictScalars.map_apply f] change s • (g y) = g (s • y) rw [map_smul] @@ -539,24 +536,21 @@ protected def unit' : 𝟭 (ModuleCat S) ⟶ restrictScalars f ⋙ coextendScala /-- The natural transformation from the composition of coextension and restriction of scalars to identity functor. -/ --- @[simps] Porting note: not in normal form and not used +@[simps] protected def counit' : coextendScalars f ⋙ restrictScalars f ⟶ 𝟭 (ModuleCat R) where - app X := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(X := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + app X := ofHom (X := (restrictScalars f).obj ((coextendScalars f).obj X)) { toFun := fun g => g.toFun (1 : S) map_add' := fun x1 x2 => by dsimp rw [LinearMap.add_apply] map_smul' := fun r (g : (restrictScalars f).obj ((coextendScalars f).obj X)) => by dsimp - rw [← LinearMap.coe_toAddHom, ← AddHom.toFun_eq_coe] - rw [CoextendScalars.smul_apply (s := f r) (g := g) (s' := 1), one_mul, ← LinearMap.map_smul] - rw [← LinearMap.coe_toAddHom, ← AddHom.toFun_eq_coe] + rw [CoextendScalars.smul_apply, one_mul, ← LinearMap.map_smul] congr change f r = (f r) • (1 : S) rw [smul_eq_mul (a := f r) (a' := 1), mul_one] } - naturality X X' g := LinearMap.ext fun h => by - rw [ModuleCat.coe_comp] - rfl end RestrictionCoextensionAdj @@ -569,26 +563,18 @@ def restrictCoextendScalarsAdj {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] homEquiv := fun X Y ↦ { toFun := RestrictionCoextensionAdj.HomEquiv.fromRestriction.{u₁,u₂,v} f invFun := RestrictionCoextensionAdj.HomEquiv.toRestriction.{u₁,u₂,v} f - left_inv := fun g => LinearMap.ext fun x : X => by - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10745): once just simp - rw [RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe, - LinearMap.coe_toAddHom, RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply, - one_smul] - right_inv := fun g => LinearMap.ext fun x => LinearMap.ext fun s : S => by + left_inv := fun g => by ext; simp + right_inv := fun g => hom_ext <| LinearMap.ext fun x => LinearMap.ext fun s : S => by -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10745): once just simp - rw [RestrictionCoextensionAdj.HomEquiv.fromRestriction_apply_apply, - RestrictionCoextensionAdj.HomEquiv.toRestriction_apply, AddHom.toFun_eq_coe, - LinearMap.coe_toAddHom, LinearMap.map_smulₛₗ, RingHom.id_apply, - CoextendScalars.smul_apply', one_mul] } + rw [RestrictionCoextensionAdj.HomEquiv.fromRestriction_hom_apply_apply, + RestrictionCoextensionAdj.HomEquiv.toRestriction_hom_apply, LinearMap.map_smulₛₗ, + RingHom.id_apply, CoextendScalars.smul_apply', one_mul] } unit := RestrictionCoextensionAdj.unit'.{u₁,u₂,v} f counit := RestrictionCoextensionAdj.counit'.{u₁,u₂,v} f - homEquiv_unit := LinearMap.ext fun _ => rfl - homEquiv_counit := fun {X Y g} => LinearMap.ext <| by - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10745): previously simp [RestrictionCoextensionAdj.counit'] - intro x; dsimp - rw [coe_comp, Function.comp] - change _ = (((restrictScalars f).map g) x).toFun (1 : S) - rw [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, restrictScalars.map_apply] } + homEquiv_unit := hom_ext <| LinearMap.ext fun _ => rfl + homEquiv_counit := fun {X Y g} => by + ext + simp [RestrictionCoextensionAdj.counit'] } instance {R : Type u₁} {S : Type u₂} [Ring R] [Ring S] (f : R →+* S) : (restrictScalars.{max u₂ w} f).IsLeftAdjoint := @@ -611,17 +597,20 @@ Given `R`-module X and `S`-module Y and a map `g : (extendScalars f).obj X ⟶ Y map `S ⨂ X → Y`, there is a `X ⟶ (restrictScalars f).obj Y`, i.e. `R`-linear map `X ⟶ Y` by `x ↦ g (1 ⊗ x)`. -/ -@[simps apply] +@[simps hom_apply] def HomEquiv.toRestrictScalars {X Y} (g : (extendScalars f).obj X ⟶ Y) : - X ⟶ (restrictScalars f).obj Y where - toFun x := g <| (1 : S)⊗ₜ[R,f]x - map_add' _ _ := by dsimp; rw [tmul_add, map_add] - map_smul' r x := by - letI : Module R S := Module.compHom S f - letI : Module R Y := Module.compHom Y f - dsimp - erw [RestrictScalars.smul_def, ← LinearMap.map_smul, tmul_smul] - congr + X ⟶ (restrictScalars f).obj Y := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + ofHom (Y := (restrictScalars f).obj Y) + { toFun := fun x => g <| (1 : S)⊗ₜ[R,f]x + map_add' := fun _ _ => by dsimp; rw [tmul_add, map_add] + map_smul' := fun r s => by + letI : Module R S := Module.compHom S f + letI : Module R Y := Module.compHom Y f + dsimp + erw [RestrictScalars.smul_def, ← LinearMap.map_smul, tmul_smul] + congr } -- Porting note: forced to break apart fromExtendScalars due to timeouts /-- @@ -636,7 +625,7 @@ def HomEquiv.evalAt {X : ModuleCat R} {Y : ModuleCat S} (s : S) map_add' := by intros dsimp only - rw [map_add,smul_add] } + rw [map_add, smul_add] } (by intros r x rw [AddHom.toFun_eq_coe, AddHom.coe_mk, RingHom.id_apply, @@ -647,16 +636,16 @@ Given `R`-module X and `S`-module Y and a map `X ⟶ (restrictScalars f).obj Y`, `X ⟶ Y`, there is a map `(extend_scalars f).obj X ⟶ Y`, i.e `S`-linear map `S ⨂ X → Y` by `s ⊗ x ↦ s • g x`. -/ -@[simps apply] +@[simps hom_apply] def HomEquiv.fromExtendScalars {X Y} (g : X ⟶ (restrictScalars f).obj Y) : (extendScalars f).obj X ⟶ Y := by letI m1 : Module R S := Module.compHom S f; letI m2 : Module R Y := Module.compHom Y f - refine {toFun := fun z => TensorProduct.lift ?_ z, map_add' := ?_, map_smul' := ?_} + refine ofHom {toFun := fun z => TensorProduct.lift ?_ z, map_add' := ?_, map_smul' := ?_} · refine {toFun := fun s => HomEquiv.evalAt f s g, map_add' := fun (s₁ s₂ : S) => ?_, map_smul' := fun (r : R) (s : S) => ?_} · ext - dsimp only [evalAt_apply, LinearMap.add_apply] + dsimp only [m2, evalAt_apply, LinearMap.add_apply] rw [← add_smul] · ext x apply mul_smul (f r) s (g x) @@ -685,6 +674,7 @@ def homEquiv {X Y} : invFun := HomEquiv.fromExtendScalars.{u₁,u₂,v} f left_inv g := by letI m1 : Module R S := Module.compHom S f; letI m2 : Module R Y := Module.compHom Y f + apply hom_ext apply LinearMap.ext; intro z induction z using TensorProduct.induction_on with | zero => rw [map_zero, map_zero] @@ -698,9 +688,11 @@ def homEquiv {X Y} : | add _ _ ih1 ih2 => rw [map_add, map_add, ih1, ih2] right_inv g := by letI m1 : Module R S := Module.compHom S f; letI m2 : Module R Y := Module.compHom Y f - apply LinearMap.ext; intro x - rw [HomEquiv.toRestrictScalars_apply, HomEquiv.fromExtendScalars_apply, lift.tmul, - LinearMap.coe_mk, LinearMap.coe_mk] + ext x + rw [HomEquiv.toRestrictScalars_hom_apply] + -- This needs to be `erw` because of some unfolding in `fromExtendScalars` + erw [HomEquiv.fromExtendScalars_hom_apply] + rw [lift.tmul, LinearMap.coe_mk, LinearMap.coe_mk] dsimp rw [one_smul] @@ -708,13 +700,16 @@ def homEquiv {X Y} : For any `R`-module X, there is a natural `R`-linear map from `X` to `X ⨂ S` by sending `x ↦ x ⊗ 1` -/ -- @[simps] Porting note: not in normal form and not used -def Unit.map {X} : X ⟶ (extendScalars f ⋙ restrictScalars f).obj X where - toFun x := (1 : S)⊗ₜ[R,f]x - map_add' x x' := by dsimp; rw [TensorProduct.tmul_add] - map_smul' r x := by - letI m1 : Module R S := Module.compHom S f - -- Porting note: used to be rfl - dsimp; rw [← TensorProduct.smul_tmul,TensorProduct.smul_tmul'] +def Unit.map {X} : X ⟶ (extendScalars f ⋙ restrictScalars f).obj X := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + ofHom (Y := (extendScalars f ⋙ restrictScalars f).obj X) + { toFun := fun x => (1 : S)⊗ₜ[R,f]x + map_add' := fun x x' => by dsimp; rw [TensorProduct.tmul_add] + map_smul' := fun r x => by + letI m1 : Module R S := Module.compHom S f + -- Porting note: used to be rfl + dsimp; rw [← TensorProduct.smul_tmul,TensorProduct.smul_tmul'] } /-- The natural transformation from identity functor on `R`-module to the composition of extension and @@ -726,45 +721,41 @@ def unit : 𝟭 (ModuleCat R) ⟶ extendScalars f ⋙ restrictScalars.{max v u /-- For any `S`-module Y, there is a natural `R`-linear map from `S ⨂ Y` to `Y` by `s ⊗ y ↦ s • y` -/ -@[simps apply] -def Counit.map {Y} : (restrictScalars f ⋙ extendScalars f).obj Y ⟶ Y where - toFun := - letI m1 : Module R S := Module.compHom S f - letI m2 : Module R Y := Module.compHom Y f - TensorProduct.lift - { toFun := fun s : S => - { toFun := fun y : Y => s • y, - map_add' := smul_add _ - map_smul' := fun r y => by - change s • f r • y = f r • s • y - rw [← mul_smul, mul_comm, mul_smul] }, - map_add' := fun s₁ s₂ => by - ext y - change (s₁ + s₂) • y = s₁ • y + s₂ • y - rw [add_smul] - map_smul' := fun r s => by - ext y - change (f r • s) • y = (f r) • s • y - rw [smul_eq_mul, mul_smul] } - map_add' _ _ := by rw [map_add] - map_smul' s z := by - letI m1 : Module R S := Module.compHom S f - letI m2 : Module R Y := Module.compHom Y f - dsimp only - induction z using TensorProduct.induction_on with - | zero => rw [smul_zero, map_zero, smul_zero] - | tmul s' y => - rw [ExtendScalars.smul_tmul, LinearMap.coe_mk] - erw [TensorProduct.lift.tmul, TensorProduct.lift.tmul] - set s' : S := s' - change (s * s') • y = s • s' • y - rw [mul_smul] - | add _ _ ih1 ih2 => rw [smul_add, map_add, map_add, ih1, ih2, smul_add] - --- Porting note: this file has to probably be reworked when --- coercions and instance synthesis are fixed for concrete categories --- so I say nolint now and move on -attribute [nolint simpNF] Counit.map_apply +@[simps hom_apply] +def Counit.map {Y} : (restrictScalars f ⋙ extendScalars f).obj Y ⟶ Y := + ofHom + { toFun := + letI m1 : Module R S := Module.compHom S f + letI m2 : Module R Y := Module.compHom Y f + TensorProduct.lift + { toFun := fun s : S => + { toFun := fun y : Y => s • y, + map_add' := smul_add _ + map_smul' := fun r y => by + change s • f r • y = f r • s • y + rw [← mul_smul, mul_comm, mul_smul] }, + map_add' := fun s₁ s₂ => by + ext y + change (s₁ + s₂) • y = s₁ • y + s₂ • y + rw [add_smul] + map_smul' := fun r s => by + ext y + change (f r • s) • y = (f r) • s • y + rw [smul_eq_mul, mul_smul] } + map_add' := fun _ _ => by rw [map_add] + map_smul' := fun s z => by + letI m1 : Module R S := Module.compHom S f + letI m2 : Module R Y := Module.compHom Y f + dsimp only + induction z using TensorProduct.induction_on with + | zero => rw [smul_zero, map_zero, smul_zero] + | tmul s' y => + rw [ExtendScalars.smul_tmul, LinearMap.coe_mk] + erw [TensorProduct.lift.tmul, TensorProduct.lift.tmul] + set s' : S := s' + change (s * s') • y = s • s' • y + rw [mul_smul] + | add _ _ ih1 ih2 => rw [smul_add, map_add, map_add, ih1, ih2, smul_add] } /-- The natural transformation from the composition of restriction and extension of scalars to the identity functor on `S`-module. @@ -777,15 +768,13 @@ def counit : restrictScalars.{max v u₂,u₁,u₂} f ⋙ extendScalars f ⟶ letI m1 : Module R S := Module.compHom S f letI m2 : Module R Y := Module.compHom Y f letI m2 : Module R Y' := Module.compHom Y' f - apply LinearMap.ext; intro z + ext z induction z using TensorProduct.induction_on with | zero => rw [map_zero, map_zero] | tmul s' y => dsimp - rw [ModuleCat.coe_comp, ModuleCat.coe_comp, Function.comp_apply, Function.comp_apply, - ExtendScalars.map_tmul, restrictScalars.map_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [Counit.map_apply] + erw [Counit.map_hom_apply] rw [lift.tmul, LinearMap.coe_mk, LinearMap.coe_mk] set s' : S := s' change s' • g y = g (s' • y) @@ -803,20 +792,18 @@ def extendRestrictScalarsAdj {R : Type u₁} {S : Type u₂} [CommRing R] [CommR homEquiv := fun _ _ ↦ ExtendRestrictScalarsAdj.homEquiv.{v,u₁,u₂} f unit := ExtendRestrictScalarsAdj.unit.{v,u₁,u₂} f counit := ExtendRestrictScalarsAdj.counit.{v,u₁,u₂} f - homEquiv_unit := fun {X Y g} ↦ LinearMap.ext fun x => by + homEquiv_unit := fun {X Y g} ↦ hom_ext <| LinearMap.ext fun x => by dsimp - rw [ModuleCat.coe_comp, Function.comp_apply, restrictScalars.map_apply] rfl - homEquiv_counit := fun {X Y g} ↦ LinearMap.ext fun x => by + homEquiv_counit := fun {X Y g} ↦ hom_ext <| LinearMap.ext fun x => by induction x using TensorProduct.induction_on with | zero => rw [map_zero, map_zero] | tmul => rw [ExtendRestrictScalarsAdj.homEquiv_symm_apply] dsimp - rw [ModuleCat.coe_comp, Function.comp_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [ExtendRestrictScalarsAdj.Counit.map_apply] - dsimp + erw [ExtendRestrictScalarsAdj.Counit.map_hom_apply, + ExtendRestrictScalarsAdj.HomEquiv.fromExtendScalars_hom_apply] | add => rw [map_add, map_add]; congr 1 } instance {R : Type u₁} {S : Type u₂} [CommRing R] [CommRing S] (f : R →+* S) : diff --git a/Mathlib/Algebra/Category/ModuleCat/Differentials/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Differentials/Basic.lean index 323f048f1af4a..a0ca4297cf81c 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Differentials/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Differentials/Basic.lean @@ -99,9 +99,9 @@ variable (f) in /-- The (universal) derivation in `(KaehlerDifferential f).Derivation f` when `f : A ⟶ B` is a morphism in the category `CommRingCat`. -/ noncomputable def D : (KaehlerDifferential f).Derivation f := - letI := f.toAlgebra + letI algebra := f.toAlgebra ModuleCat.Derivation.mk - (fun b ↦ _root_.KaehlerDifferential.D A B b) (by simp) (by simp) + (fun b ↦ _root_.KaehlerDifferential.D A B b) (by simp [algebra]) (by simp [algebra]) (_root_.KaehlerDifferential.D A B).map_algebraMap /-- When `f : A ⟶ B` is a morphism in the category `CommRingCat`, this is the @@ -112,12 +112,13 @@ noncomputable abbrev d (b : B) : KaehlerDifferential f := (D f).d b lemma ext {M : ModuleCat B} {α β : KaehlerDifferential f ⟶ M} (h : ∀ (b : B), α (d b) = β (d b)) : α = β := by rw [← sub_eq_zero] - have : ⊤ ≤ LinearMap.ker (α - β) := by + have : ⊤ ≤ LinearMap.ker (α - β).hom := by rw [← KaehlerDifferential.span_range_derivation, Submodule.span_le] rintro _ ⟨y, rfl⟩ - rw [SetLike.mem_coe, LinearMap.mem_ker, LinearMap.sub_apply, sub_eq_zero] + rw [SetLike.mem_coe, LinearMap.mem_ker, ModuleCat.hom_sub, LinearMap.sub_apply, sub_eq_zero] apply h rw [top_le_iff, LinearMap.ker_eq_top] at this + ext : 1 exact this /-- The map `KaehlerDifferential f ⟶ (ModuleCat.restrictScalars g').obj (KaehlerDifferential f')` @@ -133,6 +134,9 @@ noncomputable def map : letI := (g ≫ f').toAlgebra have : IsScalarTower A A' B' := IsScalarTower.of_algebraMap_eq' rfl have := IsScalarTower.of_algebraMap_eq' fac + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + ModuleCat.ofHom (Y := (ModuleCat.restrictScalars g').obj (KaehlerDifferential f')) { toFun := fun x ↦ _root_.KaehlerDifferential.map A A' B B' x map_add' := by simp map_smul' := by simp } @@ -163,7 +167,7 @@ morphism `CommRingCat.KaehlerDifferential f ⟶ M`. -/ noncomputable def desc : CommRingCat.KaehlerDifferential f ⟶ M := letI := f.toAlgebra letI := Module.compHom M f - D.liftKaehlerDifferential + ofHom D.liftKaehlerDifferential @[simp] lemma desc_d (b : B) : D.desc (CommRingCat.KaehlerDifferential.d b) = D.d b := by diff --git a/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean index 5ea1401c768c2..9df2e8a46993e 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Differentials/Presheaf.lean @@ -77,7 +77,7 @@ variable (d : M.Derivation φ) /-- The postcomposition of a derivation by a morphism of presheaves of modules. -/ @[simps! d_apply] def postcomp (f : M ⟶ N) : N.Derivation φ where - d := (f.app _).toAddMonoidHom.comp d.d + d := (f.app _).hom.toAddMonoidHom.comp d.d d_map {X Y} g x := by simpa using naturality_apply f g (d.d x) d_app {X} a := by dsimp @@ -191,7 +191,7 @@ attribute [simp] relativeDifferentials'_obj lemma relativeDifferentials'_map_d {X Y : Dᵒᵖ} (f : X ⟶ Y) (x : R.obj X) : DFunLike.coe (α := CommRingCat.KaehlerDifferential (φ'.app X)) (β := fun _ ↦ CommRingCat.KaehlerDifferential (φ'.app Y)) - ((relativeDifferentials' φ').map f) (CommRingCat.KaehlerDifferential.d x) = + ((relativeDifferentials' φ').map f).hom (CommRingCat.KaehlerDifferential.d x) = CommRingCat.KaehlerDifferential.d (R.map f x) := CommRingCat.KaehlerDifferential.map_d (φ'.naturality f) _ diff --git a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean index 4ba5ef78289de..c6db67923b764 100644 --- a/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean +++ b/Mathlib/Algebra/Category/ModuleCat/EpiMono.lean @@ -24,22 +24,24 @@ namespace ModuleCat variable {R : Type u} [Ring R] {X Y : ModuleCat.{v} R} (f : X ⟶ Y) variable {M : Type v} [AddCommGroup M] [Module R M] -theorem ker_eq_bot_of_mono [Mono f] : LinearMap.ker f = ⊥ := - LinearMap.ker_eq_bot_of_cancel fun u v => (@cancel_mono _ _ _ _ _ f _ (↟u) (↟v)).1 +theorem ker_eq_bot_of_mono [Mono f] : LinearMap.ker f.hom = ⊥ := + LinearMap.ker_eq_bot_of_cancel fun u v h => ModuleCat.hom_ext_iff.mp <| + (@cancel_mono _ _ _ _ _ f _ (↟u) (↟v)).1 <| ModuleCat.hom_ext_iff.mpr h -theorem range_eq_top_of_epi [Epi f] : LinearMap.range f = ⊤ := - LinearMap.range_eq_top_of_cancel fun u v => (@cancel_epi _ _ _ _ _ f _ (↟u) (↟v)).1 +theorem range_eq_top_of_epi [Epi f] : LinearMap.range f.hom = ⊤ := + LinearMap.range_eq_top_of_cancel fun u v h => ModuleCat.hom_ext_iff.mp <| + (@cancel_epi _ _ _ _ _ f _ (↟u) (↟v)).1 <| ModuleCat.hom_ext_iff.mpr h -theorem mono_iff_ker_eq_bot : Mono f ↔ LinearMap.ker f = ⊥ := +theorem mono_iff_ker_eq_bot : Mono f ↔ LinearMap.ker f.hom = ⊥ := ⟨fun _ => ker_eq_bot_of_mono _, fun hf => ConcreteCategory.mono_of_injective _ <| by convert LinearMap.ker_eq_bot.1 hf⟩ theorem mono_iff_injective : Mono f ↔ Function.Injective f := by rw [mono_iff_ker_eq_bot, LinearMap.ker_eq_bot] -theorem epi_iff_range_eq_top : Epi f ↔ LinearMap.range f = ⊤ := +theorem epi_iff_range_eq_top : Epi f ↔ LinearMap.range f.hom = ⊤ := ⟨fun _ => range_eq_top_of_epi _, fun hf => - ConcreteCategory.epi_of_surjective _ <| LinearMap.range_eq_top.1 hf⟩ + ConcreteCategory.epi_of_surjective _ <| by convert LinearMap.range_eq_top.1 hf⟩ theorem epi_iff_surjective : Epi f ↔ Function.Surjective f := by rw [epi_iff_range_eq_top, LinearMap.range_eq_top] @@ -48,10 +50,10 @@ theorem epi_iff_surjective : Epi f ↔ Function.Surjective f := by def uniqueOfEpiZero (X) [h : Epi (0 : X ⟶ of R M)] : Unique M := uniqueOfSurjectiveZero X ((ModuleCat.epi_iff_surjective _).mp h) -instance mono_as_hom'_subtype (U : Submodule R X) : Mono (ModuleCat.asHomRight U.subtype) := +instance mono_as_hom'_subtype (U : Submodule R X) : Mono (ModuleCat.ofHom U.subtype) := (mono_iff_ker_eq_bot _).mpr (Submodule.ker_subtype U) -instance epi_as_hom''_mkQ (U : Submodule R X) : Epi (↿U.mkQ) := +instance epi_as_hom''_mkQ (U : Submodule R X) : Epi (ModuleCat.ofHom U.mkQ) := (epi_iff_range_eq_top _).mpr <| Submodule.range_mkQ _ instance forget_preservesEpimorphisms : (forget (ModuleCat.{v} R)).PreservesEpimorphisms where diff --git a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean index 553ce84f4002e..08ca1ad384315 100644 --- a/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/FilteredColimits.lean @@ -132,7 +132,8 @@ def colimit : ModuleCatMax.{v, u, u} R := /-- The linear map from a given `R`-module in the diagram to the colimit module. -/ def coconeMorphism (j : J) : F.obj j ⟶ colimit F := - { (AddCommGrp.FilteredColimits.colimitCocone + ofHom + { (AddCommGrp.FilteredColimits.colimitCocone (F ⋙ forget₂ (ModuleCat R) AddCommGrp.{max v u})).ι.app j with map_smul' := fun r x => by erw [colimit_smul_mk_eq F r ⟨j, x⟩]; rfl } @@ -142,7 +143,7 @@ def colimitCocone : Cocone F where ι := { app := coconeMorphism F naturality := fun _ _' f => - LinearMap.coe_injective + hom_ext <| LinearMap.coe_injective ((Types.TypeMax.colimitCocone (F ⋙ forget (ModuleCat R))).ι.naturality f) } /-- Given a cocone `t` of `F`, the induced monoid linear map from the colimit to the cocone point. @@ -150,25 +151,27 @@ We already know that this is a morphism between additive groups. The only thing it is a linear map, i.e. preserves scalar multiplication. -/ def colimitDesc (t : Cocone F) : colimit F ⟶ t.pt := - { (AddCommGrp.FilteredColimits.colimitCoconeIsColimit + ofHom + { (AddCommGrp.FilteredColimits.colimitCoconeIsColimit (F ⋙ forget₂ (ModuleCatMax.{v, u} R) AddCommGrp.{max v u})).desc ((forget₂ (ModuleCat R) AddCommGrp.{max v u}).mapCocone t) with map_smul' := fun r x => by refine Quot.inductionOn x ?_; clear x; intro x; obtain ⟨j, x⟩ := x erw [colimit_smul_mk_eq] - exact LinearMap.map_smul (t.ι.app j) r x } + exact LinearMap.map_smul (t.ι.app j).hom r x } /-- The proposed colimit cocone is a colimit in `ModuleCat R`. -/ def colimitCoconeIsColimit : IsColimit (colimitCocone F) where desc := colimitDesc F fac t j := - LinearMap.coe_injective <| + hom_ext <| LinearMap.coe_injective <| (Types.TypeMax.colimitCoconeIsColimit.{v, u} (F ⋙ forget (ModuleCat R))).fac ((forget (ModuleCat R)).mapCocone t) j uniq t _ h := - LinearMap.coe_injective <| + hom_ext <| LinearMap.coe_injective <| (Types.TypeMax.colimitCoconeIsColimit (F ⋙ forget (ModuleCat R))).uniq - ((forget (ModuleCat R)).mapCocone t) _ fun j => funext fun x => LinearMap.congr_fun (h j) x + ((forget (ModuleCat R)).mapCocone t) _ fun j => funext fun x => LinearMap.congr_fun + (ModuleCat.hom_ext_iff.mp (h j)) x instance forget₂AddCommGroup_preservesFilteredColimits : PreservesFilteredColimits (forget₂ (ModuleCat.{u} R) AddCommGrp.{u}) where diff --git a/Mathlib/Algebra/Category/ModuleCat/Free.lean b/Mathlib/Algebra/Category/ModuleCat/Free.lean index 9f822325b9425..27fcdedc44ea4 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Free.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Free.lean @@ -48,7 +48,7 @@ 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 S.f), hS.moduleCat_range_eq_ker] + rw [← LinearMap.range_coe, span_eq (LinearMap.range S.f.hom), hS.moduleCat_range_eq_ker] exact range_ker_disjoint hw include hv hm in @@ -66,8 +66,8 @@ where the top row is an exact sequence of modules and the maps on the bottom are 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 + refine ⟨?_, LinearIndependent.of_comp S.g.hom hw, disjoint_span_sum hS hw huv⟩ + rw [huv, LinearMap.linearIndependent_iff S.f.hom]; swap · rw [LinearMap.ker_eq_bot, ← mono_iff_injective] infer_instance exact hv @@ -78,7 +78,7 @@ include hS' hv in /-- 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 : ι' → S.X₃} (hw : LinearIndependent R w) : - LinearIndependent R (Sum.elim (S.f ∘ v) (S.g.toFun.invFun ∘ w)) := by + LinearIndependent R (Sum.elim (S.f ∘ v) (S.g.hom.toFun.invFun ∘ w)) := by apply linearIndependent_leftExact hS'.exact hv _ hS'.mono_f rfl dsimp convert hw @@ -109,7 +109,7 @@ theorem span_exact {β : Type*} {u : ι ⊕ β → S.X₂} (huv : u ∘ Sum.inl rw [Finsupp.mem_span_range_iff_exists_finsupp] at hgm obtain ⟨cm, hm⟩ := hgm let m' : S.X₂ := Finsupp.sum cm fun j a ↦ a • (u (Sum.inr j)) - have hsub : m - m' ∈ LinearMap.range S.f := by + have hsub : m - m' ∈ LinearMap.range S.f.hom := by rw [hS.moduleCat_range_eq_ker] simp only [LinearMap.mem_ker, map_sub, sub_eq_zero] rw [← hm, map_finsupp_sum] @@ -138,7 +138,7 @@ include hS in 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 + ⊤ ≤ span R (range (Sum.elim (S.f ∘ v) (S.g.hom.toFun.invFun ∘ w))) := by refine span_exact hS ?_ hv ?_ · simp only [AddHom.toFun_eq_coe, LinearMap.coe_toAddHom, Sum.elim_comp_inl] · convert hw diff --git a/Mathlib/Algebra/Category/ModuleCat/Images.lean b/Mathlib/Algebra/Category/ModuleCat/Images.lean index 9a516ef12b9b4..17f0387b646f9 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Images.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Images.lean @@ -32,18 +32,18 @@ section -- implementation details of `HasImage` for ModuleCat; use the API, not these /-- The image of a morphism in `ModuleCat R` is just the bundling of `LinearMap.range f` -/ def image : ModuleCat R := - ModuleCat.of R (LinearMap.range f) + ModuleCat.of R (LinearMap.range f.hom) /-- The inclusion of `image f` into the target -/ def image.ι : image f ⟶ H := - f.range.subtype + ofHom f.hom.range.subtype instance : Mono (image.ι f) := ConcreteCategory.mono_of_injective (image.ι f) Subtype.val_injective /-- The corestriction map to the image -/ def factorThruImage : G ⟶ image f := - f.rangeRestrict + ofHom f.hom.rangeRestrict theorem image.fac : factorThruImage f ≫ image.ι f = f := rfl @@ -53,22 +53,23 @@ attribute [local simp] image.fac variable {f} /-- The universal property for the image factorisation -/ -noncomputable def image.lift (F' : MonoFactorisation f) : image f ⟶ F'.I where - toFun := (fun x => F'.e (Classical.indefiniteDescription _ x.2).1 : image f → F'.I) - map_add' x y := by - apply (mono_iff_injective F'.m).1 - · infer_instance - rw [LinearMap.map_add] - change (F'.e ≫ F'.m) _ = (F'.e ≫ F'.m) _ + (F'.e ≫ F'.m) _ - simp_rw [F'.fac, (Classical.indefiniteDescription (fun z => f z = _) _).2] - rfl - map_smul' c x := by - apply (mono_iff_injective F'.m).1 - · infer_instance - rw [LinearMap.map_smul] - change (F'.e ≫ F'.m) _ = _ • (F'.e ≫ F'.m) _ - simp_rw [F'.fac, (Classical.indefiniteDescription (fun z => f z = _) _).2] - rfl +noncomputable def image.lift (F' : MonoFactorisation f) : image f ⟶ F'.I := + ofHom + { toFun := (fun x => F'.e (Classical.indefiniteDescription _ x.2).1 : image f → F'.I) + map_add' := fun x y => by + apply (mono_iff_injective F'.m).1 + · infer_instance + rw [LinearMap.map_add] + change (F'.e ≫ F'.m) _ = (F'.e ≫ F'.m) _ + (F'.e ≫ F'.m) _ + simp_rw [F'.fac, (Classical.indefiniteDescription (fun z => f z = _) _).2] + rfl + map_smul' := fun c x => by + apply (mono_iff_injective F'.m).1 + · infer_instance + rw [LinearMap.map_smul] + change (F'.e ≫ F'.m) _ = _ • (F'.e ≫ F'.m) _ + simp_rw [F'.fac, (Classical.indefiniteDescription (fun z => f z = _) _).2] + rfl } theorem image.lift_fac (F' : MonoFactorisation f) : image.lift F' ≫ F'.m = image.ι f := by ext x @@ -92,17 +93,17 @@ noncomputable def isImage : IsImage (monoFactorisation f) where /-- The categorical image of a morphism in `ModuleCat R` agrees with the linear algebraic range. -/ noncomputable def imageIsoRange {G H : ModuleCat.{v} R} (f : G ⟶ H) : - Limits.image f ≅ ModuleCat.of R (LinearMap.range f) := + Limits.image f ≅ ModuleCat.of R (LinearMap.range f.hom) := IsImage.isoExt (Image.isImage f) (isImage f) @[simp, reassoc, elementwise] theorem imageIsoRange_inv_image_ι {G H : ModuleCat.{v} R} (f : G ⟶ H) : - (imageIsoRange f).inv ≫ Limits.image.ι f = ModuleCat.asHom f.range.subtype := + (imageIsoRange f).inv ≫ Limits.image.ι f = ModuleCat.ofHom f.hom.range.subtype := IsImage.isoExt_inv_m _ _ @[simp, reassoc, elementwise] theorem imageIsoRange_hom_subtype {G H : ModuleCat.{v} R} (f : G ⟶ H) : - (imageIsoRange f).hom ≫ ModuleCat.asHom f.range.subtype = Limits.image.ι f := by + (imageIsoRange f).hom ≫ ModuleCat.ofHom f.hom.range.subtype = Limits.image.ι f := by rw [← imageIsoRange_inv_image_ι f, Iso.hom_inv_id_assoc] end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Injective.lean b/Mathlib/Algebra/Category/ModuleCat/Injective.lean index f579799501b6a..e11b9d7185a1f 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Injective.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Injective.lean @@ -20,16 +20,17 @@ namespace Module theorem injective_object_of_injective_module [inj : Injective R M] : CategoryTheory.Injective (ModuleCat.of R M) where factors g f m := - have ⟨l, h⟩ := inj.out f ((ModuleCat.mono_iff_injective f).mp m) g - ⟨l, LinearMap.ext h⟩ + have ⟨l, h⟩ := inj.out f.hom ((ModuleCat.mono_iff_injective f).mp m) g.hom + ⟨ModuleCat.ofHom l, by ext x; simpa using h x⟩ theorem injective_module_of_injective_object [inj : CategoryTheory.Injective <| ModuleCat.of R M] : Module.Injective R M where out X Y _ _ _ _ f hf g := by - have : CategoryTheory.Mono (ModuleCat.asHom f) := (ModuleCat.mono_iff_injective _).mpr hf - obtain ⟨l, rfl⟩ := inj.factors (ModuleCat.asHom g) (ModuleCat.asHom f) - exact ⟨l, fun _ ↦ rfl⟩ + have : CategoryTheory.Mono (ModuleCat.ofHom f) := (ModuleCat.mono_iff_injective _).mpr hf + obtain ⟨l, h⟩ := inj.factors (ModuleCat.ofHom g) (ModuleCat.ofHom f) + obtain rfl := ModuleCat.hom_ext_iff.mp h + exact ⟨l.hom, fun _ => rfl⟩ theorem injective_iff_injective_object : Module.Injective R M ↔ diff --git a/Mathlib/Algebra/Category/ModuleCat/Kernels.lean b/Mathlib/Algebra/Category/ModuleCat/Kernels.lean index 0a06c74a2fe68..6f2398e63fd4f 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Kernels.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Kernels.lean @@ -26,40 +26,38 @@ variable {M N : ModuleCat.{v} R} (f : M ⟶ N) /-- The kernel cone induced by the concrete kernel. -/ def kernelCone : KernelFork f := -- Porting note: previously proven by tidy - KernelFork.ofι (asHom f.ker.subtype) <| by ext x; cases x; assumption + KernelFork.ofι (ofHom f.hom.ker.subtype) <| by ext x; cases x; assumption /-- The kernel of a linear map is a kernel in the categorical sense. -/ def kernelIsLimit : IsLimit (kernelCone f) := Fork.IsLimit.mk _ - (fun s => + (fun s => ofHom <| -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation on LinearMap.ker - LinearMap.codRestrict (LinearMap.ker f) (Fork.ι s) fun c => + LinearMap.codRestrict (LinearMap.ker f.hom) (Fork.ι s).hom fun c => LinearMap.mem_ker.2 <| by -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [← @Function.comp_apply _ _ _ f (Fork.ι s) c, ← coe_comp] - rw [Fork.condition, HasZeroMorphisms.comp_zero (Fork.ι s) N] + erw [← @Function.comp_apply _ _ _ f (Fork.ι s) c, ← LinearMap.coe_comp] + rw [← ModuleCat.hom_comp, Fork.condition, HasZeroMorphisms.comp_zero (Fork.ι s) N] rfl) - (fun _ => LinearMap.subtype_comp_codRestrict _ _ _) fun s m h => - LinearMap.ext fun x => Subtype.ext_iff_val.2 (by simp [← h]; rfl) + (fun _ => hom_ext <| LinearMap.subtype_comp_codRestrict _ _ _) fun s m h => + hom_ext <| LinearMap.ext fun x => Subtype.ext_iff_val.2 (by simp [← h]; rfl) /-- The cokernel cocone induced by the projection onto the quotient. -/ def cokernelCocone : CokernelCofork f := - CokernelCofork.ofπ (asHom f.range.mkQ) <| LinearMap.range_mkQ_comp _ + CokernelCofork.ofπ (ofHom f.hom.range.mkQ) <| hom_ext <| LinearMap.range_mkQ_comp _ /-- The projection onto the quotient is a cokernel in the categorical sense. -/ def cokernelIsColimit : IsColimit (cokernelCocone f) := Cofork.IsColimit.mk _ - (fun s => - f.range.liftQ (Cofork.π s) <| LinearMap.range_le_ker_iff.2 <| CokernelCofork.condition s) - (fun s => f.range.liftQ_mkQ (Cofork.π s) _) fun s m h => by + (fun s => ofHom <| f.hom.range.liftQ (Cofork.π s).hom <| + LinearMap.range_le_ker_iff.2 <| ModuleCat.hom_ext_iff.mp <| CokernelCofork.condition s) + (fun s => hom_ext <| f.hom.range.liftQ_mkQ (Cofork.π s).hom _) fun s m h => by -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation - haveI : Epi (asHom (LinearMap.range f).mkQ) := + haveI : Epi (ofHom (LinearMap.range f.hom).mkQ) := (epi_iff_range_eq_top _).mpr (Submodule.range_mkQ _) -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation - apply (cancel_epi (asHom (LinearMap.range f).mkQ)).1 - convert h - -- Porting note: no longer necessary - -- exact Submodule.liftQ_mkQ _ _ _ + apply (cancel_epi (ofHom (LinearMap.range f.hom).mkQ)).1 + exact h end @@ -84,20 +82,20 @@ agrees with the usual module-theoretical kernel. -/ noncomputable def kernelIsoKer {G H : ModuleCat.{v} R} (f : G ⟶ H) : -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation - kernel f ≅ ModuleCat.of R (LinearMap.ker f) := + kernel f ≅ ModuleCat.of R (LinearMap.ker f.hom) := limit.isoLimitCone ⟨_, kernelIsLimit f⟩ -- We now show this isomorphism commutes with the inclusion of the kernel into the source. @[simp, elementwise] -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation theorem kernelIsoKer_inv_kernel_ι : (kernelIsoKer f).inv ≫ kernel.ι f = - (LinearMap.ker f).subtype := + ofHom (LinearMap.ker f.hom).subtype := limit.isoLimitCone_inv_π _ _ @[simp, elementwise] theorem kernelIsoKer_hom_ker_subtype : -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation - (kernelIsoKer f).hom ≫ (LinearMap.ker f).subtype = kernel.ι f := + (kernelIsoKer f).hom ≫ ofHom (LinearMap.ker f.hom).subtype = kernel.ι f := IsLimit.conePointUniqueUpToIso_inv_comp _ (limit.isLimit _) WalkingParallelPair.zero /-- The categorical cokernel of a morphism in `ModuleCat` @@ -105,18 +103,18 @@ agrees with the usual module-theoretical quotient. -/ noncomputable def cokernelIsoRangeQuotient {G H : ModuleCat.{v} R} (f : G ⟶ H) : -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11036): broken dot notation - cokernel f ≅ ModuleCat.of R (H ⧸ LinearMap.range f) := + cokernel f ≅ ModuleCat.of R (H ⧸ LinearMap.range f.hom) := colimit.isoColimitCocone ⟨_, cokernelIsColimit f⟩ -- We now show this isomorphism commutes with the projection of target to the cokernel. @[simp, elementwise] theorem cokernel_π_cokernelIsoRangeQuotient_hom : - cokernel.π f ≫ (cokernelIsoRangeQuotient f).hom = f.range.mkQ := + cokernel.π f ≫ (cokernelIsoRangeQuotient f).hom = ofHom f.hom.range.mkQ := colimit.isoColimitCocone_ι_hom _ _ @[simp, elementwise] theorem range_mkQ_cokernelIsoRangeQuotient_inv : - ↿f.range.mkQ ≫ (cokernelIsoRangeQuotient f).inv = cokernel.π f := + ofHom f.hom.range.mkQ ≫ (cokernelIsoRangeQuotient f).inv = cokernel.π f := colimit.isoColimitCocone_ι_inv ⟨_, cokernelIsColimit f⟩ WalkingParallelPair.one theorem cokernel_π_ext {M N : ModuleCat.{u} R} (f : M ⟶ N) {x y : N} (m : M) (w : x = y + f m) : diff --git a/Mathlib/Algebra/Category/ModuleCat/Limits.lean b/Mathlib/Algebra/Category/ModuleCat/Limits.lean index 862547dd00ba8..607ca41120826 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Limits.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Limits.lean @@ -45,9 +45,7 @@ def sectionsSubmodule : Submodule R (∀ j, F.obj j) := forget₂ AddCommGrp AddGrp.{w}) with carrier := (F ⋙ forget (ModuleCat R)).sections smul_mem' := fun r s sh j j' f => by - simp only [forget_map, Functor.comp_map, Pi.smul_apply, map_smul] - dsimp [Functor.sections] at sh - rw [sh f] } + simpa [Functor.sections, forget_map] using congr_arg (r • ·) (sh f) } instance : AddCommMonoid (F ⋙ forget (ModuleCat R)).sections := inferInstanceAs <| AddCommMonoid (sectionsSubmodule F) @@ -101,16 +99,16 @@ namespace HasLimits def limitCone : Cone F where pt := ModuleCat.of R (Types.Small.limitCone.{v, w} (F ⋙ forget _)).pt π := - { app := limitπLinearMap F - naturality := fun _ _ f => - LinearMap.coe_injective ((Types.Small.limitCone (F ⋙ forget _)).π.naturality f) } + { app := fun j => ofHom (limitπLinearMap F j) + naturality := fun _ _ f => hom_ext <| LinearMap.coe_injective <| + ((Types.Small.limitCone (F ⋙ forget _)).π.naturality f) } /-- Witness that the limit cone in `ModuleCat R` is a limit cone. (Internal use only; use the limits API.) -/ def limitConeIsLimit : IsLimit (limitCone.{t, v, w} F) := by refine IsLimit.ofFaithful (forget (ModuleCat R)) (Types.Small.limitConeIsLimit.{v, w} _) - (fun s => ⟨⟨(Types.Small.limitConeIsLimit.{v, w} _).lift + (fun s => ofHom ⟨⟨(Types.Small.limitConeIsLimit.{v, w} _).lift ((forget (ModuleCat R)).mapCone s), ?_⟩, ?_⟩) (fun s => rfl) · intro x y @@ -216,14 +214,12 @@ variable (f : ∀ i j, i ≤ j → G i →ₗ[R] G j) [DirectedSystem G fun i j @[simps] def directLimitDiagram : ι ⥤ ModuleCat R where obj i := ModuleCat.of R (G i) - map hij := f _ _ hij.le + map hij := ofHom (f _ _ hij.le) map_id i := by - apply LinearMap.ext - intro x + ext apply Module.DirectedSystem.map_self map_comp hij hjk := by - apply LinearMap.ext - intro x + ext symm apply Module.DirectedSystem.map_map @@ -237,35 +233,33 @@ In `directLimitIsColimit` we show that it is a colimit cocone. -/ def directLimitCocone : Cocone (directLimitDiagram G f) where pt := ModuleCat.of R <| DirectLimit G f ι := - { app := Module.DirectLimit.of R ι G f + { app := fun x => ofHom (Module.DirectLimit.of R ι G f x) naturality := fun _ _ hij => by - apply LinearMap.ext - intro x + ext exact DirectLimit.of_f } /-- The unbundled `directLimit` of modules is a colimit in the sense of `CategoryTheory`. -/ @[simps] def directLimitIsColimit [IsDirected ι (· ≤ ·)] : IsColimit (directLimitCocone G f) where - desc s := - DirectLimit.lift R ι G f s.ι.app fun i j h x => by + desc s := ofHom <| + DirectLimit.lift R ι G f (fun i => (s.ι.app i).hom) fun i j h x => by + simp only [Functor.const_obj_obj] rw [← s.w (homOfLE h)] rfl fac s i := by - apply LinearMap.ext - intro x + ext dsimp only [directLimitCocone, CategoryStruct.comp] rw [LinearMap.comp_apply] apply DirectLimit.lift_of uniq s m h := by have : s.ι.app = fun i => - LinearMap.comp m (DirectLimit.of R ι (fun i => G i) (fun i j H => f i j H) i) := by + (ofHom (DirectLimit.of R ι (fun i => G i) (fun i j H => f i j H) i)) ≫ m := by funext i rw [← h] rfl - apply LinearMap.ext - intro x + ext simp only [this] apply Module.DirectLimit.lift_unique diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean index d6e565553b5e4..89bdba339ff9f 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Basic.lean @@ -54,25 +54,27 @@ def tensorObj (M N : ModuleCat R) : ModuleCat R := /-- (implementation) tensor product of morphisms R-modules -/ def tensorHom {M N M' N' : ModuleCat R} (f : M ⟶ N) (g : M' ⟶ N') : tensorObj M M' ⟶ tensorObj N N' := - TensorProduct.map f g + ofHom <| TensorProduct.map f.hom g.hom /-- (implementation) left whiskering for R-modules -/ def whiskerLeft (M : ModuleCat R) {N₁ N₂ : ModuleCat R} (f : N₁ ⟶ N₂) : tensorObj M N₁ ⟶ tensorObj M N₂ := - f.lTensor M + ofHom <| f.hom.lTensor M /-- (implementation) right whiskering for R-modules -/ def whiskerRight {M₁ M₂ : ModuleCat R} (f : M₁ ⟶ M₂) (N : ModuleCat R) : tensorObj M₁ N ⟶ tensorObj M₂ N := - f.rTensor N + ofHom <| f.hom.rTensor N theorem tensor_id (M N : ModuleCat R) : tensorHom (𝟙 M) (𝟙 N) = 𝟙 (ModuleCat.of R (M ⊗ N)) := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): even with high priority `ext` fails to find this. apply TensorProduct.ext rfl theorem tensor_comp {X₁ Y₁ Z₁ X₂ Y₂ Z₂ : ModuleCat R} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (g₁ : Y₁ ⟶ Z₁) (g₂ : Y₂ ⟶ Z₂) : tensorHom (f₁ ≫ g₁) (f₂ ≫ g₂) = tensorHom f₁ f₂ ≫ tensorHom g₁ g₂ := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): even with high priority `ext` fails to find this. apply TensorProduct.ext rfl @@ -95,63 +97,36 @@ instance instMonoidalCategoryStruct : MonoidalCategoryStruct (ModuleCat.{u} R) w tensorObj := tensorObj whiskerLeft := whiskerLeft whiskerRight := whiskerRight - tensorHom f g := TensorProduct.map f g + tensorHom f g := ofHom <| TensorProduct.map f.hom g.hom tensorUnit := ModuleCat.of R R associator := associator leftUnitor := leftUnitor rightUnitor := rightUnitor -section - -/-! The `associator_naturality` and `pentagon` lemmas below are very slow to elaborate. - -We give them some help by expressing the lemmas first non-categorically, then using -`convert _aux using 1` to have the elaborator work as little as possible. -/ - - -open TensorProduct (assoc map) - -private theorem associator_naturality_aux {X₁ X₂ X₃ : Type*} [AddCommMonoid X₁] [AddCommMonoid X₂] - [AddCommMonoid X₃] [Module R X₁] [Module R X₂] [Module R X₃] {Y₁ Y₂ Y₃ : Type*} - [AddCommMonoid Y₁] [AddCommMonoid Y₂] [AddCommMonoid Y₃] [Module R Y₁] [Module R Y₂] - [Module R Y₃] (f₁ : X₁ →ₗ[R] Y₁) (f₂ : X₂ →ₗ[R] Y₂) (f₃ : X₃ →ₗ[R] Y₃) : - ↑(assoc R Y₁ Y₂ Y₃) ∘ₗ map (map f₁ f₂) f₃ = map f₁ (map f₂ f₃) ∘ₗ ↑(assoc R X₁ X₂ X₃) := by - apply TensorProduct.ext_threefold - intro x y z - rfl - -variable (R) - -private theorem pentagon_aux (W X Y Z : Type*) [AddCommMonoid W] [AddCommMonoid X] - [AddCommMonoid Y] [AddCommMonoid Z] [Module R W] [Module R X] [Module R Y] [Module R Z] : - (((assoc R X Y Z).toLinearMap.lTensor W).comp - (assoc R W (X ⊗[R] Y) Z).toLinearMap).comp - ((assoc R W X Y).toLinearMap.rTensor Z) = - (assoc R W X (Y ⊗[R] Z)).toLinearMap.comp (assoc R (W ⊗[R] X) Y Z).toLinearMap := by - apply TensorProduct.ext_fourfold - intro w x y z - rfl - -end - theorem associator_naturality {X₁ X₂ X₃ Y₁ Y₂ Y₃ : ModuleCat R} (f₁ : X₁ ⟶ Y₁) (f₂ : X₂ ⟶ Y₂) (f₃ : X₃ ⟶ Y₃) : tensorHom (tensorHom f₁ f₂) f₃ ≫ (associator Y₁ Y₂ Y₃).hom = (associator X₁ X₂ X₃).hom ≫ tensorHom f₁ (tensorHom f₂ f₃) := by - convert associator_naturality_aux f₁ f₂ f₃ using 1 + ext : 1 + apply TensorProduct.ext_threefold + intro x y z + rfl theorem pentagon (W X Y Z : ModuleCat R) : whiskerRight (associator W X Y).hom Z ≫ (associator W (tensorObj X Y) Z).hom ≫ whiskerLeft W (associator X Y Z).hom = (associator (tensorObj W X) Y Z).hom ≫ (associator W X (tensorObj Y Z)).hom := by - convert pentagon_aux R W X Y Z using 1 + ext : 1 + apply TensorProduct.ext_fourfold + intro w x y z + rfl theorem leftUnitor_naturality {M N : ModuleCat R} (f : M ⟶ N) : tensorHom (𝟙 (ModuleCat.of R R)) f ≫ (leftUnitor N).hom = (leftUnitor M).hom ≫ f := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): broken ext apply TensorProduct.ext - apply LinearMap.ext_ring - apply LinearMap.ext; intro x + ext x -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10934): used to be dsimp change ((leftUnitor N).hom) ((tensorHom (𝟙 (of R R)) f) ((1 : R) ⊗ₜ[R] x)) = f (((leftUnitor M).hom) (1 ⊗ₜ[R] x)) @@ -161,13 +136,11 @@ theorem leftUnitor_naturality {M N : ModuleCat R} (f : M ⟶ N) : theorem rightUnitor_naturality {M N : ModuleCat R} (f : M ⟶ N) : tensorHom f (𝟙 (ModuleCat.of R R)) ≫ (rightUnitor N).hom = (rightUnitor M).hom ≫ f := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/pull/11041): broken ext apply TensorProduct.ext - apply LinearMap.ext; intro x - apply LinearMap.ext_ring - -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10934): used to be dsimp - change ((rightUnitor N).hom) ((tensorHom f (𝟙 (of R R))) (x ⊗ₜ[R] (1 : R))) = - f (((rightUnitor M).hom) (x ⊗ₜ[R] 1)) + ext x + dsimp erw [TensorProduct.rid_tmul, TensorProduct.rid_tmul] rw [LinearMap.map_smul] rfl @@ -175,9 +148,9 @@ theorem rightUnitor_naturality {M N : ModuleCat R} (f : M ⟶ N) : theorem triangle (M N : ModuleCat.{u} R) : (associator M (ModuleCat.of R R) N).hom ≫ tensorHom (𝟙 M) (leftUnitor N).hom = tensorHom (rightUnitor M).hom (𝟙 N) := by + ext : 1 apply TensorProduct.ext_threefold intro x y z - change R at y -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10934): used to be dsimp [tensorHom, associator] change x ⊗ₜ[R] ((leftUnitor N).hom) (y ⊗ₜ[R] z) = ((rightUnitor M).hom) (x ⊗ₜ[R] y) ⊗ₜ[R] z erw [TensorProduct.lid_tmul, TensorProduct.rid_tmul] @@ -263,7 +236,7 @@ variable (f : M₁ → M₂ → M₃) (h₁ : ∀ m₁ m₂ n, f (m₁ + m₂) n /-- Construct for morphisms from the tensor product of two objects in `ModuleCat`. -/ noncomputable def tensorLift : M₁ ⊗ M₂ ⟶ M₃ := - TensorProduct.lift (LinearMap.mk₂ R f h₁ h₂ h₃ h₄) + ofHom <| TensorProduct.lift (LinearMap.mk₂ R f h₁ h₂ h₃ h₄) @[simp] lemma tensorLift_tmul (m : M₁) (n : M₂) : @@ -273,13 +246,13 @@ end lemma tensor_ext {f g : M₁ ⊗ M₂ ⟶ M₃} (h : ∀ m n, f (m ⊗ₜ n) = g (m ⊗ₜ n)) : f = g := - TensorProduct.ext (by ext; apply h) + hom_ext <| TensorProduct.ext (by ext; apply h) /-- Extensionality lemma for morphisms from a module of the form `(M₁ ⊗ M₂) ⊗ M₃`. -/ lemma tensor_ext₃' {f g : (M₁ ⊗ M₂) ⊗ M₃ ⟶ M₄} (h : ∀ m₁ m₂ m₃, f (m₁ ⊗ₜ m₂ ⊗ₜ m₃) = g (m₁ ⊗ₜ m₂ ⊗ₜ m₃)) : f = g := - TensorProduct.ext_threefold h + hom_ext <| TensorProduct.ext_threefold h /-- Extensionality lemma for morphisms from a module of the form `M₁ ⊗ (M₂ ⊗ M₃)`. -/ lemma tensor_ext₃ {f g : M₁ ⊗ (M₂ ⊗ M₃) ⟶ M₄} @@ -292,56 +265,57 @@ end MonoidalCategory open Opposite --- Porting note: simp wasn't firing but rw was, annoying instance : MonoidalPreadditive (ModuleCat.{u} R) := by refine ⟨?_, ?_, ?_, ?_⟩ · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.zero_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_zero, LinearMap.zero_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerLeft_apply] - rw [LinearMap.zero_apply, TensorProduct.tmul_zero] + simp · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.zero_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_zero, LinearMap.zero_apply, ] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerRight_apply] - rw [LinearMap.zero_apply, TensorProduct.zero_tmul] + simp · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.add_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_add, LinearMap.add_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerLeft_apply, MonoidalCategory.whiskerLeft_apply] erw [MonoidalCategory.whiskerLeft_apply] - rw [LinearMap.add_apply, TensorProduct.tmul_add] + simp [TensorProduct.tmul_add] · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.add_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_add, LinearMap.add_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerRight_apply, MonoidalCategory.whiskerRight_apply] erw [MonoidalCategory.whiskerRight_apply] - rw [LinearMap.add_apply, TensorProduct.add_tmul] + simp [TensorProduct.add_tmul] --- Porting note: simp wasn't firing but rw was, annoying instance : MonoidalLinear R (ModuleCat.{u} R) := by refine ⟨?_, ?_⟩ · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.smul_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_smul, LinearMap.smul_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerLeft_apply, MonoidalCategory.whiskerLeft_apply] - rw [LinearMap.smul_apply, TensorProduct.tmul_smul] + simp · intros + ext : 1 refine TensorProduct.ext (LinearMap.ext fun x => LinearMap.ext fun y => ?_) - simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply] - rw [LinearMap.smul_apply] + simp only [LinearMap.compr₂_apply, TensorProduct.mk_apply, hom_smul, LinearMap.smul_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [MonoidalCategory.whiskerRight_apply, MonoidalCategory.whiskerRight_apply] - rw [LinearMap.smul_apply, TensorProduct.smul_tmul, TensorProduct.tmul_smul] + simp [TensorProduct.smul_tmul, TensorProduct.tmul_smul] + +@[simp] lemma ofHom₂_compr₂ {M N P Q : ModuleCat.{u} R} (f : M →ₗ[R] N →ₗ[R] P) (g : P →ₗ[R] Q): + ofHom₂ (f.compr₂ g) = ofHom₂ f ≫ ofHom (Linear.rightComp R _ (ofHom g)) := rfl end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean index 3b8592dcc5ce7..61228a85b17e0 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Closed.lean @@ -27,15 +27,13 @@ variable {R : Type u} [CommRing R] def monoidalClosedHomEquiv (M N P : ModuleCat.{u} R) : ((MonoidalCategory.tensorLeft M).obj N ⟶ P) ≃ (N ⟶ ((linearCoyoneda R (ModuleCat R)).obj (op M)).obj P) where - toFun f := LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f) - invFun f := (β_ M N).hom ≫ TensorProduct.lift f + toFun f := ofHom₂ <| LinearMap.compr₂ (TensorProduct.mk R N M) ((β_ N M).hom ≫ f).hom + invFun f := (β_ M N).hom ≫ ofHom (TensorProduct.lift f.hom₂) left_inv f := by + ext : 1 apply TensorProduct.ext' intro m n - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [coe_comp] - rw [Function.comp_apply] - -- This used to be `rw` and was longer (?), but we need `erw` after https://github.com/leanprover/lean4/pull/2644 + simp only [Hom.hom₂_ofHom₂, LinearMap.comp_apply, hom_comp, MonoidalCategory.tensorLeft_obj] erw [MonoidalCategory.braiding_hom_apply, TensorProduct.lift.tmul] right_inv _ := rfl @@ -47,6 +45,7 @@ instance : MonoidalClosed (ModuleCat.{u} R) where -- Porting note: this proof was automatic in mathlib3 homEquiv_naturality_left_symm := by intros + ext : 1 apply TensorProduct.ext' intro m n rfl } } @@ -57,26 +56,24 @@ theorem ihom_map_apply {M N P : ModuleCat.{u} R} (f : N ⟶ P) (g : ModuleCat.of open MonoidalCategory --- Porting note: `CoeFun` was replaced by `DFunLike` --- I can't seem to express the function coercion here without writing `@DFunLike.coe`. theorem monoidalClosed_curry {M N P : ModuleCat.{u} R} (f : M ⊗ N ⟶ P) (x : M) (y : N) : - @DFunLike.coe _ _ _ LinearMap.instFunLike - ((MonoidalClosed.curry f : N →ₗ[R] M →ₗ[R] P) y) x = f (x ⊗ₜ[R] y) := + ((MonoidalClosed.curry f).hom y).hom x = f (x ⊗ₜ[R] y) := rfl @[simp] theorem monoidalClosed_uncurry {M N P : ModuleCat.{u} R} (f : N ⟶ M ⟶[ModuleCat.{u} R] P) (x : M) (y : N) : - MonoidalClosed.uncurry f (x ⊗ₜ[R] y) = - @DFunLike.coe _ _ _ LinearMap.instFunLike (f y) x := + MonoidalClosed.uncurry f (x ⊗ₜ[R] y) = (f y).hom x := rfl /-- Describes the counit of the adjunction `M ⊗ - ⊣ Hom(M, -)`. Given an `R`-module `N` this should give a map `M ⊗ Hom(M, N) ⟶ N`, so we flip the order of the arguments in the identity map `Hom(M, N) ⟶ (M ⟶ N)` and uncurry the resulting map `M ⟶ Hom(M, N) ⟶ N.` -/ theorem ihom_ev_app (M N : ModuleCat.{u} R) : - (ihom.ev M).app N = TensorProduct.uncurry _ _ _ _ LinearMap.id.flip := by + (ihom.ev M).app N = ModuleCat.ofHom (TensorProduct.uncurry R M ((ihom M).obj N) N + (LinearMap.lcomp _ _ homLinearEquiv.toLinearMap ∘ₗ LinearMap.id.flip)) := by rw [← MonoidalClosed.uncurry_id_eq_ev] + ext : 1 apply TensorProduct.ext' apply monoidalClosed_uncurry @@ -84,11 +81,12 @@ theorem ihom_ev_app (M N : ModuleCat.{u} R) : define a map `N ⟶ Hom(M, M ⊗ N)`, which is given by flipping the arguments in the natural `R`-bilinear map `M ⟶ N ⟶ M ⊗ N`. -/ theorem ihom_coev_app (M N : ModuleCat.{u} R) : - (ihom.coev M).app N = (TensorProduct.mk _ _ _).flip := + (ihom.coev M).app N = ModuleCat.ofHom₂ (TensorProduct.mk _ _ _).flip := rfl theorem monoidalClosed_pre_app {M N : ModuleCat.{u} R} (P : ModuleCat.{u} R) (f : N ⟶ M) : - (MonoidalClosed.pre f).app P = LinearMap.lcomp R _ f := + (MonoidalClosed.pre f).app P = ofHom (homLinearEquiv.symm.toLinearMap ∘ₗ + LinearMap.lcomp _ _ f.hom ∘ₗ homLinearEquiv.toLinearMap) := rfl end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean index d6b5c46f9dba1..42370456d2060 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Monoidal/Symmetric.lean @@ -29,6 +29,7 @@ namespace MonoidalCategory @[simp] theorem braiding_naturality {X₁ X₂ Y₁ Y₂ : ModuleCat.{u} R} (f : X₁ ⟶ Y₁) (g : X₂ ⟶ Y₂) : (f ⊗ g) ≫ (Y₁.braiding Y₂).hom = (X₁.braiding X₂).hom ≫ (g ⊗ f) := by + ext : 1 apply TensorProduct.ext' intro x y rfl @@ -49,6 +50,7 @@ theorem braiding_naturality_right (X : ModuleCat R) {Y Z : ModuleCat R} (f : Y theorem hexagon_forward (X Y Z : ModuleCat.{u} R) : (α_ X Y Z).hom ≫ (braiding X _).hom ≫ (α_ Y Z X).hom = (braiding X Y).hom ▷ Z ≫ (α_ Y X Z).hom ≫ Y ◁ (braiding X Z).hom := by + ext : 1 apply TensorProduct.ext_threefold intro x y z rfl @@ -58,6 +60,7 @@ theorem hexagon_reverse (X Y Z : ModuleCat.{u} R) : (α_ X Y Z).inv ≫ (braiding _ Z).hom ≫ (α_ Z X Y).inv = X ◁ (Y.braiding Z).hom ≫ (α_ X Z Y).inv ≫ (X.braiding Z).hom ▷ Y := by apply (cancel_epi (α_ X Y Z).hom).1 + ext : 1 apply TensorProduct.ext_threefold intro x y z rfl @@ -74,6 +77,7 @@ instance symmetricCategory : SymmetricCategory (ModuleCat.{u} R) where -- Porting note: this proof was automatic in Lean3 -- now `aesop` is applying `ModuleCat.ext` in favour of `TensorProduct.ext`. symmetry _ _ := by + ext : 1 apply TensorProduct.ext' aesop_cat @@ -88,8 +92,8 @@ theorem braiding_inv_apply {M N : ModuleCat.{u} R} (m : M) (n : N) : rfl theorem tensorμ_eq_tensorTensorTensorComm {A B C D : ModuleCat R} : - tensorμ A B C D = (TensorProduct.tensorTensorTensorComm R A B C D).toLinearMap := - TensorProduct.ext <| TensorProduct.ext <| LinearMap.ext₂ fun _ _ => + tensorμ A B C D = ofHom (TensorProduct.tensorTensorTensorComm R A B C D).toLinearMap := + ModuleCat.hom_ext <| TensorProduct.ext <| TensorProduct.ext <| LinearMap.ext₂ fun _ _ => TensorProduct.ext <| LinearMap.ext₂ fun _ _ => rfl @[simp] diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean index 653280c6b57bd..8755d8d2ac2f7 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf.lean @@ -161,7 +161,10 @@ when the preferred constructor `PresheafOfModules.mk` is not as convenient as th @[simps] def ofPresheaf : PresheafOfModules.{v} R where obj X := ModuleCat.of _ (M.obj X) - map f := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + map {X Y} f := ModuleCat.ofHom + (Y := (ModuleCat.restrictScalars (R.map f)).obj (ModuleCat.of _ (M.obj Y))) { toFun := fun x ↦ M.map f x map_add' := by simp map_smul' := fun r m ↦ map_smul f r m } @@ -178,7 +181,7 @@ which satisfy a suitable linearity condition. -/ def homMk (φ : M₁.presheaf ⟶ M₂.presheaf) (hφ : ∀ (X : Cᵒᵖ) (r : R.obj X) (m : M₁.obj X), φ.app X (r • m) = r • φ.app X m) : M₁ ⟶ M₂ where - app X := + app X := ModuleCat.ofHom { toFun := φ.app X map_add' := by simp map_smul' := hφ X } @@ -197,30 +200,21 @@ instance : Neg (M₁ ⟶ M₂) where { app := fun X ↦ -f.app X naturality := fun {X Y} h ↦ by ext x - dsimp - erw [map_neg] - rw [← naturality_apply] - rfl } + simp [← naturality_apply] } instance : Add (M₁ ⟶ M₂) where add f g := { app := fun X ↦ f.app X + g.app X naturality := fun {X Y} h ↦ by ext x - dsimp - erw [map_add] - rw [← naturality_apply, ← naturality_apply] - rfl } + simp [← naturality_apply] } instance : Sub (M₁ ⟶ M₂) where sub f g := { app := fun X ↦ f.app X - g.app X naturality := fun {X Y} h ↦ by ext x - dsimp - erw [map_sub] - rw [← naturality_apply, ← naturality_apply] - rfl } + simp [← naturality_apply] } @[simp] lemma neg_app (f : M₁ ⟶ M₂) (X : Cᵒᵖ) : (-f).app X = -f.app X := rfl @[simp] lemma add_app (f g : M₁ ⟶ M₂) (X : Cᵒᵖ) : (f + g).app X = f.app X + g.app X := rfl @@ -267,7 +261,10 @@ noncomputable def restriction {X Y : Cᵒᵖ} (f : X ⟶ Y) : /-- The obvious free presheaf of modules of rank `1`. -/ def unit : PresheafOfModules R where obj X := ModuleCat.of _ (R.obj X) - map {X Y } f := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + map {X Y} f := ModuleCat.ofHom + (Y := (ModuleCat.restrictScalars (R.map f)).obj (ModuleCat.of (R.obj Y) (R.obj Y))) { toFun := fun x ↦ R.map f x map_add' := by simp map_smul' := by aesop_cat } @@ -321,14 +318,16 @@ def unitHomEquiv (M : PresheafOfModules R) : toFun f := sectionsMk (fun X ↦ Hom.app f X (1 : R.obj X)) (by intros; rw [← naturality_apply, unit_map_one]) invFun s := - { app := fun X ↦ (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm (s.val X) + { app := fun X ↦ ModuleCat.ofHom + ((LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm (s.val X)) naturality := fun {X Y} f ↦ by - ext (x : R.obj X) - change R.map f x • s.eval Y = M.map f (x • s.eval X) + ext + dsimp + change R.map f 1 • s.eval Y = M.map f (1 • s.eval X) simp } left_inv f := by - ext1 X - exact (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm_apply_apply (f.app X) + ext X : 2 + exact (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).symm_apply_apply (f.app X).hom right_inv s := by ext X exact (LinearMap.ringLmapEquivSelf (R.obj X) ℤ (M.obj X)).apply_symm_apply (s.val X) @@ -352,27 +351,29 @@ variable (M : PresheafOfModules.{v} R) noncomputable abbrev forgetToPresheafModuleCatObjObj (Y : Cᵒᵖ) : ModuleCat (R.obj X) := (ModuleCat.restrictScalars (R.map (hX.to Y))).obj (M.obj Y) -@[simp] +-- This should not be a `simp` lemma because `M.obj Y` is missing the `Module (R.obj X)` instance, +-- so `simp`ing breaks downstream proofs. lemma forgetToPresheafModuleCatObjObj_coe (Y : Cᵒᵖ) : (forgetToPresheafModuleCatObjObj X hX M Y : Type _) = M.obj Y := rfl /-- Auxiliary definition for `forgetToPresheafModuleCatObj`. -/ def forgetToPresheafModuleCatObjMap {Y Z : Cᵒᵖ} (f : Y ⟶ Z) : forgetToPresheafModuleCatObjObj X hX M Y ⟶ - forgetToPresheafModuleCatObjObj X hX M Z where - toFun x := M.map f x - map_add' := by simp - map_smul' r x := by - simp only [ModuleCat.restrictScalars.smul_def, AddHom.toFun_eq_coe, AddHom.coe_mk, - RingHom.id_apply, M.map_smul] - rw [← CategoryTheory.comp_apply, ← R.map_comp] - congr - apply hX.hom_ext + forgetToPresheafModuleCatObjObj X hX M Z := + ModuleCat.ofHom + (X := forgetToPresheafModuleCatObjObj X hX M Y) (Y := forgetToPresheafModuleCatObjObj X hX M Z) + { toFun := fun x => M.map f x + map_add' := by simp + map_smul' := fun r x => by + simp only [ModuleCat.restrictScalars.smul_def, AddHom.toFun_eq_coe, AddHom.coe_mk, + RingHom.id_apply, M.map_smul] + rw [← CategoryTheory.comp_apply, ← R.map_comp] + congr + apply hX.hom_ext } @[simp] lemma forgetToPresheafModuleCatObjMap_apply {Y Z : Cᵒᵖ} (f : Y ⟶ Z) (m : M.obj Y) : - DFunLike.coe (α := M.obj Y) (β := fun _ ↦ M.obj Z) - (forgetToPresheafModuleCatObjMap X hX M f) m = M.map f m := rfl + (forgetToPresheafModuleCatObjMap X hX M f).hom m = M.map f m := rfl /-- Implementation of the functor `PresheafOfModules R ⥤ Cᵒᵖ ⥤ ModuleCat (R.obj X)` @@ -402,10 +403,12 @@ morphism level `(f : M ⟶ N) ↦ (c ↦ f(c))`. noncomputable def forgetToPresheafModuleCatMap (X : Cᵒᵖ) (hX : Limits.IsInitial X) {M N : PresheafOfModules.{v} R} (f : M ⟶ N) : forgetToPresheafModuleCatObj X hX M ⟶ forgetToPresheafModuleCatObj X hX N where - app Y := + app Y := ModuleCat.ofHom + (X := (forgetToPresheafModuleCatObj X hX M).obj Y) + (Y := (forgetToPresheafModuleCatObj X hX N).obj Y) { toFun := f.app Y map_add' := by simp - map_smul' := fun r ↦ (f.app Y).map_smul (R.1.map (hX.to Y) _) } + map_smul' := fun r ↦ (f.app Y).hom.map_smul (R.1.map (hX.to Y) _) } naturality Y Z g := by ext x exact naturality_apply f g x diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean index 987578da8c709..2b6d781c0892b 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/ChangeOfRings.lean @@ -28,7 +28,12 @@ variable {C : Type u'} [Category.{v'} C] {R R' : Cᵒᵖ ⥤ RingCat.{u}} noncomputable def restrictScalarsObj (M' : PresheafOfModules.{v} R') (α : R ⟶ R') : PresheafOfModules R where obj := fun X ↦ (ModuleCat.restrictScalars (α.app X)).obj (M'.obj X) - map := fun {X Y} f ↦ + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(X := ...)` and `(Y := ...)`. + -- This suggests `restrictScalars` needs to be redesigned. + map := fun {X Y} f ↦ ModuleCat.ofHom + (X := (ModuleCat.restrictScalars (α.app X)).obj (M'.obj X)) + (Y := (ModuleCat.restrictScalars (R.map f)).obj + ((ModuleCat.restrictScalars (α.app Y)).obj (M'.obj Y))) { toFun := M'.map f map_add' := map_add _ map_smul' := fun r x ↦ (M'.map_smul f (α.app _ r) x).trans (by diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean index 2b9de6dc8f4e9..f4d23fbb2a3e3 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Monoidal.lean @@ -60,7 +60,7 @@ noncomputable def tensorObj : PresheafOfModules (R ⋙ forget₂ _ _) where intro m₁ m₂ dsimp [tensorObjMap] simp only [map_comp, Functor.comp_obj, CommRingCat.forgetToRingCat_obj, Functor.comp_map, - ModuleCat.restrictScalarsComp'_inv_app, ModuleCat.coe_comp, Function.comp_apply, + ModuleCat.restrictScalarsComp'_inv_app, ModuleCat.hom_comp, LinearMap.comp_apply, ModuleCat.restrictScalars.map_apply, ModuleCat.restrictScalarsComp'App_inv_apply] rfl) @@ -71,7 +71,7 @@ lemma tensorObj_map_tmul {X Y : Cᵒᵖ} (f : X ⟶ Y) (m₁ : M₁.obj X) (m₂ DFunLike.coe (α := (M₁.obj X ⊗ M₂.obj X : _)) (β := fun _ ↦ (ModuleCat.restrictScalars ((forget₂ CommRingCat RingCat).map (R.map f))).obj (M₁.obj Y ⊗ M₂.obj Y)) - ((tensorObj M₁ M₂).map f) (m₁ ⊗ₜ[R.obj X] m₂) = M₁.map f m₁ ⊗ₜ[R.obj Y] M₂.map f m₂ := rfl + ((tensorObj M₁ M₂).map f).hom (m₁ ⊗ₜ[R.obj X] m₂) = M₁.map f m₁ ⊗ₜ[R.obj Y] M₂.map f m₂ := rfl /-- The tensor product of two morphisms of presheaves of modules. -/ @[simps] @@ -79,10 +79,8 @@ noncomputable def tensorHom (f : M₁ ⟶ M₂) (g : M₃ ⟶ M₄) : tensorObj app X := f.app X ⊗ g.app X naturality {X Y} φ := ModuleCat.MonoidalCategory.tensor_ext (fun m₁ m₃ ↦ by dsimp - rw [tensorObj_map_tmul] - erw [ModuleCat.MonoidalCategory.tensorHom_tmul, tensorObj_map_tmul, - naturality_apply, naturality_apply] - rfl) + rw [tensorObj_map_tmul, ModuleCat.MonoidalCategory.tensorHom_tmul, tensorObj_map_tmul, + naturality_apply, naturality_apply]) end Monoidal diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean index ae8b9e272a34a..099ab943de7ac 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Pushforward.lean @@ -37,10 +37,14 @@ def pushforward₀ (R : Dᵒᵖ ⥤ RingCat.{u}) : { obj := fun X ↦ ModuleCat.of _ (M.obj (F.op.obj X)) map := fun {X Y} f ↦ M.map (F.op.map f) map_id := fun X ↦ by - ext x + refine ModuleCat.hom_ext + -- Work around an instance diamond for `restrictScalarsId'` + (@LinearMap.ext _ _ _ _ _ _ _ _ (_) (_) _ _ _ (fun x => ?_)) exact (M.congr_map_apply (F.op.map_id X) x).trans (by simp) map_comp := fun f g ↦ by - ext x + refine ModuleCat.hom_ext + -- Work around an instance diamond for `restrictScalarsId'` + (@LinearMap.ext _ _ _ _ _ _ _ _ (_) (_) _ _ _ (fun x => ?_)) exact (M.congr_map_apply (F.op.map_comp f g) x).trans (by simp) } map {M₁ M₂} φ := { app := fun X ↦ φ.app _ } @@ -66,22 +70,29 @@ noncomputable def pushforwardCompToPresheaf : pushforward.{v} φ ⋙ toPresheaf _ ≅ toPresheaf _ ⋙ (whiskeringLeft _ _ _).obj F.op := Iso.refl _ -@[simp] lemma pushforward_obj_map_apply (M : PresheafOfModules.{v} R) {X Y : Cᵒᵖ} (f : X ⟶ Y) (m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) : - DFunLike.coe - (α := (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) - (β := fun _ ↦ (ModuleCat.restrictScalars (φ.app Y)).obj - (M.obj (Opposite.op (F.obj Y.unop)))) (((pushforward φ).obj M).map f) m = - M.map (F.map f.unop).op m := rfl + (((pushforward φ).obj M).map f).hom m = M.map (F.map f.unop).op m := rfl +/-- `@[simp]`-normal form of `pushforward_obj_map_apply`. -/ @[simp] +lemma pushforward_obj_map_apply' (M : PresheafOfModules.{v} R) {X Y : Cᵒᵖ} (f : X ⟶ Y) + (m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) : + DFunLike.coe + (F := ↑((ModuleCat.restrictScalars _).obj _) →ₗ[_] + ↑((ModuleCat.restrictScalars (S.map f)).obj ((ModuleCat.restrictScalars _).obj _))) + (((pushforward φ).obj M).map f).hom m = M.map (F.map f.unop).op m := rfl + lemma pushforward_map_app_apply {M N : PresheafOfModules.{v} R} (α : M ⟶ N) (X : Cᵒᵖ) + (m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) : + (((pushforward φ).map α).app X).hom m = α.app (Opposite.op (F.obj X.unop)) m := rfl + +/-- `@[simp]`-normal form of `pushforward_map_app_apply`. -/ +@[simp] +lemma pushforward_map_app_apply' {M N : PresheafOfModules.{v} R} (α : M ⟶ N) (X : Cᵒᵖ) (m : (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) : DFunLike.coe - (α := (ModuleCat.restrictScalars (φ.app X)).obj (M.obj (Opposite.op (F.obj X.unop)))) - (β := fun _ ↦ (ModuleCat.restrictScalars (φ.app X)).obj - (N.obj (Opposite.op (F.obj X.unop)))) - (((pushforward φ).map α).app X) m = α.app (Opposite.op (F.obj X.unop)) m := rfl + (F := ↑((ModuleCat.restrictScalars _).obj _) →ₗ[_] ↑((ModuleCat.restrictScalars _).obj _)) + (((pushforward φ).map α).app X).hom m = α.app (Opposite.op (F.obj X.unop)) m := rfl end PresheafOfModules diff --git a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean index c00b766a8362d..bcf7dd4cfc6a3 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Presheaf/Sheafify.lean @@ -314,10 +314,14 @@ def toSheafify : M₀ ⟶ (restrictScalars α).obj (sheafify α φ).val := simpa using (Sheafify.map_smul_eq α φ (α.app _ r₀) (φ.app _ m₀) (𝟙 _) r₀ (by aesop) m₀ (by simp)).symm) -@[simp] lemma toSheafify_app_apply (X : Cᵒᵖ) (x : M₀.obj X) : - DFunLike.coe (α := M₀.obj X) (β := fun _ ↦ A.val.obj X) - ((toSheafify α φ).app X) x = φ.app X x := rfl + ((toSheafify α φ).app X).hom x = φ.app X x := rfl + +/-- `@[simp]`-normal form of `toSheafify_app_apply`. -/ +@[simp] +lemma toSheafify_app_apply' (X : Cᵒᵖ) (x : M₀.obj X) : + DFunLike.coe (F := (_ →ₗ[_] ↑((ModuleCat.restrictScalars (α.app X)).obj _))) + ((toSheafify α φ).app X).hom x = φ.app X x := rfl @[simp] lemma toPresheaf_map_toSheafify : (toPresheaf R₀).map (toSheafify α φ) = φ := rfl @@ -370,7 +374,7 @@ def sheafifyMap (fac : (toPresheaf R₀).map τ₀ ≫ φ' = φ ≫ τ.val) : sheafify α φ ⟶ sheafify α φ' where val := homMk τ.val (fun X r m ↦ by let f := (sheafifyHomEquiv' α φ (by exact A'.cond)).symm (τ₀ ≫ toSheafify α φ') - suffices τ.val = (toPresheaf _).map f by simpa only [this] using (f.app X).map_smul r m + suffices τ.val = (toPresheaf _).map f by simpa only [this] using (f.app X).hom.map_smul r m apply ((J.W_of_isLocallyBijective φ).homEquiv _ A'.cond).injective dsimp [f] erw [comp_toPresheaf_map_sheafifyHomEquiv'_symm_hom] diff --git a/Mathlib/Algebra/Category/ModuleCat/Products.lean b/Mathlib/Algebra/Category/ModuleCat/Products.lean index 9b504d0c1dbe0..937317e6ea0a5 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Products.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Products.lean @@ -28,18 +28,16 @@ section product /-- The product cone induced by the concrete product. -/ def productCone : Fan Z := - Fan.mk (ModuleCat.of R (∀ i : ι, Z i)) fun i => (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) + Fan.mk (ModuleCat.of R (∀ i : ι, Z i)) fun i => + ofHom (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) /-- The concrete product cone is limiting. -/ def productConeIsLimit : IsLimit (productCone Z) where - lift s := (LinearMap.pi fun j => s.π.app ⟨j⟩ : s.pt →ₗ[R] ∀ i : ι, Z i) - fac s j := by - cases j - aesop + lift s := ofHom (LinearMap.pi fun j => (s.π.app ⟨j⟩).hom : s.pt →ₗ[R] ∀ i : ι, Z i) uniq s m w := by ext x funext i - exact LinearMap.congr_fun (w ⟨i⟩) x + exact DFunLike.congr_fun (congr_arg Hom.hom (w ⟨i⟩)) x -- While we could use this to construct a `HasProducts (ModuleCat R)` instance, -- we already have `HasLimits (ModuleCat R)` in `Algebra.Category.ModuleCat.Limits`. @@ -54,12 +52,12 @@ noncomputable def piIsoPi : ∏ᶜ Z ≅ ModuleCat.of R (∀ i, Z i) := -- We now show this isomorphism commutes with the inclusion of the kernel into the source. @[simp, elementwise] theorem piIsoPi_inv_kernel_ι (i : ι) : - (piIsoPi Z).inv ≫ Pi.π Z i = (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) := + (piIsoPi Z).inv ≫ Pi.π Z i = ofHom (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) := limit.isoLimitCone_inv_π _ _ @[simp, elementwise] theorem piIsoPi_hom_ker_subtype (i : ι) : - (piIsoPi Z).hom ≫ (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) = Pi.π Z i := + (piIsoPi Z).hom ≫ ofHom (LinearMap.proj i : (∀ i : ι, Z i) →ₗ[R] Z i) = Pi.π Z i := IsLimit.conePointUniqueUpToIso_inv_comp _ (limit.isLimit _) (Discrete.mk i) end product @@ -72,19 +70,20 @@ variable [DecidableEq ι] /-- The coproduct cone induced by the concrete product. -/ def coproductCocone : Cofan Z := - Cofan.mk (ModuleCat.of R (⨁ i : ι, Z i)) fun i => (DirectSum.lof R ι (fun i ↦ Z i) i) + Cofan.mk (ModuleCat.of R (⨁ i : ι, Z i)) fun i => ofHom (DirectSum.lof R ι (fun i ↦ Z i) i) /-- The concrete coproduct cone is limiting. -/ def coproductCoconeIsColimit : IsColimit (coproductCocone Z) where - desc s := DirectSum.toModule R ι _ fun i ↦ s.ι.app ⟨i⟩ + desc s := ofHom <| DirectSum.toModule R ι _ fun i ↦ (s.ι.app ⟨i⟩).hom fac := by rintro s ⟨i⟩ ext (x : Z i) simpa only [Discrete.functor_obj_eq_as, coproductCocone, Cofan.mk_pt, Functor.const_obj_obj, - Cofan.mk_ι_app, coe_comp, Function.comp_apply] using + Cofan.mk_ι_app, hom_comp, LinearMap.coe_comp, Function.comp_apply] using DirectSum.toModule_lof (ι := ι) R (M := fun i ↦ Z i) i x uniq := by rintro s f h + ext : 1 refine DirectSum.linearMap_ext _ fun i ↦ ?_ ext x simpa only [LinearMap.coe_comp, Function.comp_apply, toModule_lof] using @@ -100,12 +99,12 @@ noncomputable def coprodIsoDirectSum : ∐ Z ≅ ModuleCat.of R (⨁ i, Z i) := @[simp, elementwise] theorem ι_coprodIsoDirectSum_hom (i : ι) : - Sigma.ι Z i ≫ (coprodIsoDirectSum Z).hom = DirectSum.lof R ι (fun i ↦ Z i) i := + Sigma.ι Z i ≫ (coprodIsoDirectSum Z).hom = ofHom (DirectSum.lof R ι (fun i ↦ Z i) i) := colimit.isoColimitCocone_ι_hom _ _ @[simp, elementwise] theorem lof_coprodIsoDirectSum_inv (i : ι) : - DirectSum.lof R ι (fun i ↦ Z i) i ≫ (coprodIsoDirectSum Z).inv = Sigma.ι Z i := + ofHom (DirectSum.lof R ι (fun i ↦ Z i) i) ≫ (coprodIsoDirectSum Z).inv = Sigma.ι Z i := (coproductCoconeIsColimit Z).comp_coconePointUniqueUpToIso_hom (colimit.isColimit _) _ end coproduct diff --git a/Mathlib/Algebra/Category/ModuleCat/Projective.lean b/Mathlib/Algebra/Category/ModuleCat/Projective.lean index e8bfc43488358..1947ab1f393c3 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Projective.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Projective.lean @@ -30,13 +30,16 @@ theorem IsProjective.iff_projective {R : Type u} [Ring R] {P : Type max u v} [Ad [Module R P] : Module.Projective R P ↔ Projective (ModuleCat.of R P) := by refine ⟨fun h => ?_, fun h => ?_⟩ · letI : Module.Projective R (ModuleCat.of R P) := h - exact ⟨fun E X epi => Module.projective_lifting_property _ _ - ((ModuleCat.epi_iff_surjective _).mp epi)⟩ + refine ⟨fun E X epi => ?_⟩ + obtain ⟨f, h⟩ := Module.projective_lifting_property X.hom E.hom + ((ModuleCat.epi_iff_surjective _).mp epi) + exact ⟨ofHom f, hom_ext h⟩ · refine Module.Projective.of_lifting_property.{u,v} ?_ intro E X mE mX sE sX f g s haveI : Epi (↟f) := (ModuleCat.epi_iff_surjective (↟f)).mpr s letI : Projective (ModuleCat.of R P) := h - exact ⟨Projective.factorThru (↟g) (↟f), Projective.factorThru_comp (↟g) (↟f)⟩ + exact ⟨(Projective.factorThru (↟g) (↟f)).hom, + ModuleCat.hom_ext_iff.mp <| Projective.factorThru_comp (↟g) (↟f)⟩ namespace ModuleCat @@ -56,15 +59,9 @@ instance moduleCat_enoughProjectives : EnoughProjectives (ModuleCat.{max u v} R) projective := projective_of_free.{v,u} (ι := M) (M := ModuleCat.of R (M →₀ R)) <| Finsupp.basisSingleOne - f := Finsupp.basisSingleOne.constr ℕ _root_.id + f := ofHom <| Finsupp.basisSingleOne.constr ℕ _root_.id epi := (epi_iff_range_eq_top _).mpr (range_eq_top.2 fun m => ⟨Finsupp.single m (1 : R), by - -- Porting note: simp [Finsupp.linearCombination_single] fails but rw succeeds - dsimp [Basis.constr] - simp only [Finsupp.lmapDomain_id, comp_id] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [Finsupp.linearCombination_single] - rw [one_smul] - rfl ⟩) }⟩ + simp [Finsupp.linearCombination_single, Basis.constr] ⟩)}⟩ end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean index 3a23ba4b4c02e..cf467ff8b32d1 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf.lean @@ -219,7 +219,7 @@ noncomputable def homEquivOfIsLocallyBijective : (M₂ ⟶ N) ≃ (M₁ ⟶ N) w have hφ' : ∀ (z : M₂.obj X), φ.app _ (M₂.map p.op z) = N.map p.op (φ.app _ z) := congr_fun ((forget _).congr_map (φ.naturality p.op)) change N.map p.op (φ.app X (r • y)) = N.map p.op (r • φ.app X y) - rw [← hφ', M₂.map_smul, ← hx, ← (f.app _).map_smul, hφ, (ψ.app _).map_smul, + rw [← hφ', M₂.map_smul, ← hx, ← (f.app _).hom.map_smul, hφ, (ψ.app _).hom.map_smul, ← hφ, hx, N.map_smul, hφ']) left_inv φ := (toPresheaf _).map_injective (((J.W_of_isLocallyBijective diff --git a/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean b/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean index 53503eb352661..a73bfc742c383 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Sheaf/ChangeOfRings.lean @@ -59,7 +59,7 @@ noncomputable def restrictHomEquivOfIsLocallySurjective change M₂.map p.op (g.app X (r' • m)) = M₂.map p.op (r' • show M₂.obj X from g.app X m) dsimp at hg ⊢ rw [← hg, M₂.map_smul, ← hg, ← hr] - erw [← (g.app _).map_smul] + erw [← (g.app _).hom.map_smul] rw [M₁.map_smul, ← hr] rfl) left_inv _ := rfl diff --git a/Mathlib/Algebra/Category/ModuleCat/Subobject.lean b/Mathlib/Algebra/Category/ModuleCat/Subobject.lean index 0facef08450f1..3c70d7b6228ef 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Subobject.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Subobject.lean @@ -35,39 +35,37 @@ variable {R : Type u} [Ring R] (M : ModuleCat.{v} R) submodules. -/ noncomputable def subobjectModule : Subobject M ≃o Submodule R M := OrderIso.symm - { invFun := fun S => LinearMap.range S.arrow - toFun := fun N => Subobject.mk (↾N.subtype) + { invFun := fun S => LinearMap.range S.arrow.hom + toFun := fun N => Subobject.mk (ofHom N.subtype) right_inv := fun S => Eq.symm (by fapply eq_mk_of_comm - · apply LinearEquiv.toModuleIso'Left - apply LinearEquiv.ofBijective (LinearMap.codRestrict (LinearMap.range S.arrow) S.arrow _) + · apply LinearEquiv.toModuleIso + apply LinearEquiv.ofBijective (LinearMap.codRestrict + (LinearMap.range S.arrow.hom) S.arrow.hom _) constructor · simp [← LinearMap.ker_eq_bot, LinearMap.ker_codRestrict] rw [ker_eq_bot_of_mono] · rw [← LinearMap.range_eq_top, LinearMap.range_codRestrict, Submodule.comap_subtype_self] exact LinearMap.mem_range_self _ - · apply LinearMap.ext - intro x + · ext x rfl) left_inv := fun N => by - -- Porting note: The type of `↾N.subtype` was ambiguous. Not entirely sure, I made the right - -- choice here - convert congr_arg LinearMap.range - (underlyingIso_arrow (↾N.subtype : of R { x // x ∈ N } ⟶ M)) using 1 + convert congr_arg LinearMap.range (ModuleCat.hom_ext_iff.mp + (underlyingIso_arrow (ofHom N.subtype))) using 1 · have : -- Porting note: added the `.toLinearEquiv.toLinearMap` - (underlyingIso (↾N.subtype : of R _ ⟶ M)).inv = - (underlyingIso (↾N.subtype : of R _ ⟶ M)).symm.toLinearEquiv.toLinearMap := by - apply LinearMap.ext - intro x + (underlyingIso (ofHom N.subtype)).inv = + ofHom (underlyingIso (ofHom N.subtype)).symm.toLinearEquiv.toLinearMap := by + ext x rfl - rw [this, comp_def, LinearEquiv.range_comp] + rw [this, hom_comp, LinearEquiv.range_comp] · exact (Submodule.range_subtype _).symm map_rel_iff' := fun {S T} => by refine ⟨fun h => ?_, fun h => mk_le_mk_of_comm (↟(Submodule.inclusion h)) rfl⟩ - convert LinearMap.range_comp_le_range (ofMkLEMk _ _ h) (↾T.subtype) - · simpa only [← comp_def, ofMkLEMk_comp] using (Submodule.range_subtype _).symm + convert LinearMap.range_comp_le_range (ofMkLEMk _ _ h).hom (ofHom T.subtype).hom + · rw [← hom_comp, ofMkLEMk_comp] + exact (Submodule.range_subtype _).symm · exact (Submodule.range_subtype _).symm } instance wellPowered_moduleCat : WellPowered (ModuleCat.{v} R) := @@ -77,16 +75,16 @@ attribute [local instance] hasKernels_moduleCat /-- Bundle an element `m : M` such that `f m = 0` as a term of `kernelSubobject f`. -/ noncomputable def toKernelSubobject {M N : ModuleCat.{v} R} {f : M ⟶ N} : - LinearMap.ker f →ₗ[R] kernelSubobject f := - (kernelSubobjectIso f ≪≫ ModuleCat.kernelIsoKer f).inv + LinearMap.ker f.hom →ₗ[R] kernelSubobject f := + (kernelSubobjectIso f ≪≫ ModuleCat.kernelIsoKer f).inv.hom @[simp] -theorem toKernelSubobject_arrow {M N : ModuleCat R} {f : M ⟶ N} (x : LinearMap.ker f) : +theorem toKernelSubobject_arrow {M N : ModuleCat R} {f : M ⟶ N} (x : LinearMap.ker f.hom) : (kernelSubobject f).arrow (toKernelSubobject x) = x.1 := by -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10959): the whole proof was just `simp [toKernelSubobject]`. suffices ((arrow ((kernelSubobject f))) ∘ (kernelSubobjectIso f ≪≫ kernelIsoKer f).inv) x = x by convert this - rw [Iso.trans_inv, ← coe_comp, Category.assoc] + rw [Iso.trans_inv, ← LinearMap.coe_comp, ← hom_comp, Category.assoc] simp only [Category.assoc, kernelSubobject_arrow', kernelIsoKer_inv_kernel_ι] aesop_cat @@ -108,9 +106,13 @@ theorem cokernel_π_imageSubobject_ext {L M N : ModuleCat.{v} R} (f : L ⟶ M) [ subst w -- Porting note (https://github.com/leanprover-community/mathlib4/pull/10959): The proof from here used to just be `simp`. simp only [map_add, add_right_eq_self] - change ((cokernel.π g) ∘ (g) ∘ (factorThruImageSubobject f)) l = 0 - rw [← coe_comp, ← coe_comp, Category.assoc] - simp only [cokernel.condition, comp_zero] - rfl + -- TODO: add a `@[simp]` lemma along the lines of: + -- ``` + -- lemma ModuleCat.Hom.cokernel_condition : (cokernel.π g).hom (g.hom x) = 0 + -- ``` + -- ideally generated for all concrete categories (using a metaprogram like `@[elementwise]`?). + -- See also: https://github.com/leanprover-community/mathlib4/pull/19511#discussion_r1867083077 + change ((factorThruImageSubobject f) ≫ g ≫ (cokernel.π g)).hom l = 0 + simp end ModuleCat diff --git a/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean b/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean index a22898dd2560d..febe6bfa7f0fc 100644 --- a/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean +++ b/Mathlib/Algebra/Category/ModuleCat/Tannaka.lean @@ -26,10 +26,7 @@ def ringEquivEndForget₂ (R : Type u) [Ring R] : R ≃+* End (AdditiveFunctor.of (forget₂ (ModuleCat.{u} R) AddCommGrp.{u})) where toFun r := { app := fun M => - @AddCommGrp.ofHom M.carrier M.carrier _ _ (DistribMulAction.toAddMonoidHom M r) - naturality := fun M N f => by - ext - exact (f.map_smul _ _).symm } + @AddCommGrp.ofHom M.carrier M.carrier _ _ (DistribMulAction.toAddMonoidHom M r) } invFun φ := φ.app (ModuleCat.of R R) (1 : R) left_inv := by intro r @@ -39,19 +36,19 @@ def ringEquivEndForget₂ (R : Type u) [Ring R] : apply NatTrans.ext ext M (x : M) have w := congr_fun ((forget _).congr_map - (φ.naturality (ModuleCat.asHomRight (LinearMap.toSpanSingleton R M x)))) (1 : R) + (φ.naturality (ModuleCat.ofHom (LinearMap.toSpanSingleton R M x)))) (1 : R) exact w.symm.trans (congr_arg (φ.app M) (one_smul R x)) map_add' := by intros apply NatTrans.ext ext - dsimp - simp only [AddCommGrp.ofHom_apply, DistribMulAction.toAddMonoidHom_apply, add_smul] + simp only [AdditiveFunctor.of_fst, ModuleCat.forget₂_obj, AddCommGrp.coe_of, + AddCommGrp.ofHom_apply, DistribMulAction.toAddMonoidHom_apply, add_smul] rfl map_mul' := by intros apply NatTrans.ext ext - dsimp - simp only [AddCommGrp.ofHom_apply, DistribMulAction.toAddMonoidHom_apply, mul_smul] + simp only [AdditiveFunctor.of_fst, ModuleCat.forget₂_obj, AddCommGrp.coe_of, + AddCommGrp.ofHom_apply, DistribMulAction.toAddMonoidHom_apply, mul_smul] rfl diff --git a/Mathlib/Algebra/Category/Ring/Constructions.lean b/Mathlib/Algebra/Category/Ring/Constructions.lean index c124625d6a67f..8d91389010d43 100644 --- a/Mathlib/Algebra/Category/Ring/Constructions.lean +++ b/Mathlib/Algebra/Category/Ring/Constructions.lean @@ -106,8 +106,8 @@ def pushoutCoconeIsColimit : Limits.IsColimit (pushoutCocone R A B) := lemma isPushout_tensorProduct (R A B : Type u) [CommRing R] [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] : IsPushout (ofHom <| algebraMap R A) (ofHom <| algebraMap R B) - (ofHom <| Algebra.TensorProduct.includeLeftRingHom (R := R)) - (ofHom <| Algebra.TensorProduct.includeRight.toRingHom (R := R)) where + (ofHom (S := A ⊗[R] B) <| Algebra.TensorProduct.includeLeftRingHom) + (ofHom (S := A ⊗[R] B) <| Algebra.TensorProduct.includeRight.toRingHom) where w := by ext simp diff --git a/Mathlib/Algebra/Category/Ring/Epi.lean b/Mathlib/Algebra/Category/Ring/Epi.lean index eaf70a8f1b5dc..a961e33cdf72e 100644 --- a/Mathlib/Algebra/Category/Ring/Epi.lean +++ b/Mathlib/Algebra/Category/Ring/Epi.lean @@ -23,8 +23,11 @@ lemma CommRingCat.epi_iff_tmul_eq_tmul {R S : Type u} [CommRing R] [CommRing S] ∀ s : S, s ⊗ₜ[R] 1 = 1 ⊗ₜ s := by constructor · intro H + #adaptation_note + /-- After https://github.com/leanprover/lean4/pull/6024 + we need to add `(R := R) (A := S)` in the next line to deal with unification issues. -/ have := H.1 (CommRingCat.ofHom <| Algebra.TensorProduct.includeLeftRingHom (R := R)) - (CommRingCat.ofHom <| Algebra.TensorProduct.includeRight.toRingHom) + (CommRingCat.ofHom <| (Algebra.TensorProduct.includeRight (R := R) (A := S)).toRingHom) (by ext r; show algebraMap R S r ⊗ₜ 1 = 1 ⊗ₜ algebraMap R S r; simp only [Algebra.algebraMap_eq_smul_one, smul_tmul]) exact RingHom.congr_fun this diff --git a/Mathlib/Algebra/Category/Ring/Under/Limits.lean b/Mathlib/Algebra/Category/Ring/Under/Limits.lean new file mode 100644 index 0000000000000..24c129198c8b4 --- /dev/null +++ b/Mathlib/Algebra/Category/Ring/Under/Limits.lean @@ -0,0 +1,218 @@ +/- +Copyright (c) 2024 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten +-/ +import Mathlib.Algebra.Category.Ring.Under.Basic +import Mathlib.CategoryTheory.Limits.Constructions.LimitsOfProductsAndEqualizers +import Mathlib.CategoryTheory.Limits.Over +import Mathlib.RingTheory.TensorProduct.Pi +import Mathlib.RingTheory.RingHom.Flat +import Mathlib.RingTheory.Flat.Equalizer + +/-! +# Limits in `Under R` for a commutative ring `R` + +We show that `Under.pushout f` is left-exact, i.e. preserves finite limits, if `f : R ⟶ S` is +flat. + +-/ + +noncomputable section + +universe v u + +open TensorProduct CategoryTheory Limits + +variable {R S : CommRingCat.{u}} + +namespace CommRingCat.Under + +section Algebra + +variable [Algebra R S] + +section Pi + +variable {ι : Type u} (P : ι → Under R) + +/-- The canonical fan on `P : ι → Under R` given by `∀ i, P i`. -/ +def piFan : Fan P := + Fan.mk (Under.mk <| ofHom <| Pi.ringHom (fun i ↦ (P i).hom)) + (fun i ↦ Under.homMk (Pi.evalRingHom _ i)) + +/-- The canonical fan is limiting. -/ +def piFanIsLimit : IsLimit (piFan P) := + isLimitOfReflects (Under.forget R) <| + (isLimitMapConeFanMkEquiv (Under.forget R) P _).symm <| + CommRingCat.piFanIsLimit (fun i ↦ (P i).right) + +variable (S) in +/-- The fan on `i ↦ S ⊗[R] P i` given by `S ⊗[R] ∀ i, P i` -/ +def tensorProductFan : Fan (fun i ↦ mkUnder S (S ⊗[R] (P i).right)) := + Fan.mk (mkUnder S <| S ⊗[R] ∀ i, (P i).right) + (fun i ↦ AlgHom.toUnder <| + Algebra.TensorProduct.map (AlgHom.id S S) (Pi.evalAlgHom R (fun j ↦ (P j).right) i)) + +variable (S) in +/-- The fan on `i ↦ S ⊗[R] P i` given by `∀ i, S ⊗[R] P i` -/ +def tensorProductFan' : Fan (fun i ↦ mkUnder S (S ⊗[R] (P i).right)) := + Fan.mk (mkUnder S <| ∀ i, S ⊗[R] (P i).right) + (fun i ↦ AlgHom.toUnder <| Pi.evalAlgHom S _ i) + +/-- The two fans on `i ↦ S ⊗[R] P i` agree if `ι` is finite. -/ +def tensorProductFanIso [Fintype ι] [DecidableEq ι] : + tensorProductFan S P ≅ tensorProductFan' S P := + Fan.ext (Algebra.TensorProduct.piRight R S _ _).toUnder <| fun i ↦ by + dsimp only [tensorProductFan, Fan.mk_pt, fan_mk_proj, tensorProductFan'] + apply CommRingCat.mkUnder_ext + intro c + induction c + · simp only [AlgHom.toUnder_right, map_zero, Under.comp_right, comp_apply, + AlgEquiv.toUnder_hom_right_apply, Pi.evalAlgHom_apply, Pi.zero_apply] + · simp only [AlgHom.toUnder_right, Algebra.TensorProduct.map_tmul, AlgHom.coe_id, id_eq, + Pi.evalAlgHom_apply, Under.comp_right, comp_apply, AlgEquiv.toUnder_hom_right_apply, + Algebra.TensorProduct.piRight_tmul] + · simp_all + +open Classical in +/-- The fan on `i ↦ S ⊗[R] P i` given by `S ⊗[R] ∀ i, P i` is limiting if `ι` is finite. -/ +def tensorProductFanIsLimit [Finite ι] : IsLimit (tensorProductFan S P) := + letI : Fintype ι := Fintype.ofFinite ι + (IsLimit.equivIsoLimit (tensorProductFanIso P)).symm (Under.piFanIsLimit _) + +/-- `tensorProd R S` preserves the limit of the canonical fan on `P`. -/ +noncomputable -- marked noncomputable for performance (only) +def piFanTensorProductIsLimit [Finite ι] : IsLimit ((tensorProd R S).mapCone (Under.piFan P)) := + (isLimitMapConeFanMkEquiv (tensorProd R S) P _).symm <| tensorProductFanIsLimit P + +instance (J : Type u) [Finite J] (f : J → Under R) : + PreservesLimit (Discrete.functor f) (tensorProd R S) := + let c : Fan _ := Under.piFan f + have hc : IsLimit c := Under.piFanIsLimit f + preservesLimit_of_preserves_limit_cone hc (piFanTensorProductIsLimit f) + +instance (J : Type) [Finite J] : + PreservesLimitsOfShape (Discrete J) (tensorProd R S) := + let J' : Type u := ULift.{u} J + have : PreservesLimitsOfShape (Discrete J') (tensorProd R S) := + preservesLimitsOfShape_of_discrete (tensorProd R S) + let e : Discrete J' ≌ Discrete J := Discrete.equivalence Equiv.ulift + preservesLimitsOfShape_of_equiv e (R.tensorProd S) + +instance : PreservesFiniteProducts (tensorProd R S) where + preserves J := { } + +end Pi + +section Equalizer + +lemma equalizer_comp {A B : Under R} (f g : A ⟶ B) : + (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder ≫ f = + (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder ≫ g := by + ext (a : AlgHom.equalizer (toAlgHom f) (toAlgHom g)) + exact a.property + +/-- The canonical fork on `f g : A ⟶ B` given by the equalizer. -/ +def equalizerFork {A B : Under R} (f g : A ⟶ B) : + Fork f g := + Fork.ofι ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder) + (by rw [equalizer_comp]) + +@[simp] +lemma equalizerFork_ι {A B : Under R} (f g : A ⟶ B) : + (Under.equalizerFork f g).ι = (AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder := rfl + +/-- Variant of `Under.equalizerFork'` for algebra maps. This is definitionally equal to +`Under.equalizerFork` but this is costly in applications. -/ +def equalizerFork' {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] + (f g : A →ₐ[R] B) : + Fork f.toUnder g.toUnder := + Fork.ofι ((AlgHom.equalizer f g).val.toUnder) <| by ext a; exact a.property + +@[simp] +lemma equalizerFork'_ι {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] + (f g : A →ₐ[R] B) : + (Under.equalizerFork' f g).ι = (AlgHom.equalizer f g).val.toUnder := rfl + +/-- The canonical fork on `f g : A ⟶ B` is limiting. -/ +-- marked noncomputable for performance (only) +noncomputable def equalizerForkIsLimit {A B : Under R} (f g : A ⟶ B) : + IsLimit (Under.equalizerFork f g) := + isLimitOfReflects (Under.forget R) <| + (isLimitMapConeForkEquiv (Under.forget R) (equalizer_comp f g)).invFun <| + CommRingCat.equalizerForkIsLimit f.right g.right + +/-- Variant of `Under.equalizerForkIsLimit` for algebra maps. -/ +def equalizerFork'IsLimit {A B : Type u} [CommRing A] [CommRing B] [Algebra R A] + [Algebra R B] (f g : A →ₐ[R] B) : + IsLimit (Under.equalizerFork' f g) := + Under.equalizerForkIsLimit f.toUnder g.toUnder + +/-- The fork on `𝟙 ⊗[R] f` and `𝟙 ⊗[R] g` given by `S ⊗[R] eq(f, g)`. -/ +def tensorProdEqualizer {A B : Under R} (f g : A ⟶ B) : + Fork ((tensorProd R S).map f) ((tensorProd R S).map g) := + Fork.ofι + ((tensorProd R S).map ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder)) <| by + rw [← Functor.map_comp, equalizer_comp, Functor.map_comp] + +@[simp] +lemma tensorProdEqualizer_ι {A B : Under R} (f g : A ⟶ B) : + (tensorProdEqualizer f g).ι = (tensorProd R S).map + ((AlgHom.equalizer (toAlgHom f) (toAlgHom g)).val.toUnder) := + rfl + +/-- If `S` is `R`-flat, `S ⊗[R] eq(f, g)` is isomorphic to `eq(𝟙 ⊗[R] f, 𝟙 ⊗[R] g)`. -/ +-- marked noncomputable for performance (only) +noncomputable def equalizerForkTensorProdIso [Module.Flat R S] {A B : Under R} (f g : A ⟶ B) : + tensorProdEqualizer f g ≅ Under.equalizerFork' + (Algebra.TensorProduct.map (AlgHom.id S S) (toAlgHom f)) + (Algebra.TensorProduct.map (AlgHom.id S S) (toAlgHom g)) := + Fork.ext (AlgHom.tensorEqualizerEquiv S S (toAlgHom f) (toAlgHom g)).toUnder <| by + ext + apply AlgHom.coe_tensorEqualizer + +/-- If `S` is `R`-flat, `tensorProd R S` preserves the equalizer of `f` and `g`. -/ +noncomputable -- marked noncomputable for performance (only) +def tensorProdMapEqualizerForkIsLimit [Module.Flat R S] {A B : Under R} (f g : A ⟶ B) : + IsLimit ((tensorProd R S).mapCone <| Under.equalizerFork f g) := + (isLimitMapConeForkEquiv (tensorProd R S) _).symm <| + (IsLimit.equivIsoLimit (equalizerForkTensorProdIso f g).symm) <| + Under.equalizerFork'IsLimit _ _ + +instance [Module.Flat R S] {A B : Under R} (f g : A ⟶ B) : + PreservesLimit (parallelPair f g) (tensorProd R S) := + let c : Fork f g := Under.equalizerFork f g + let hc : IsLimit c := Under.equalizerForkIsLimit f g + let hc' : IsLimit ((tensorProd R S).mapCone c) := + tensorProdMapEqualizerForkIsLimit f g + preservesLimit_of_preserves_limit_cone hc hc' + +instance [Module.Flat R S] : PreservesLimitsOfShape WalkingParallelPair (tensorProd R S) where + preservesLimit {K} := + preservesLimit_of_iso_diagram _ (diagramIsoParallelPair K).symm + +instance [Module.Flat R S] : PreservesFiniteLimits (tensorProd R S) := + preservesFiniteLimits_of_preservesEqualizers_and_finiteProducts (tensorProd R S) + +end Equalizer + +end Algebra + +variable (f : R ⟶ S) + +/-- `Under.pushout f` preserves finite products. -/ +instance : PreservesFiniteProducts (Under.pushout f) where + preserves _ := + letI : Algebra R S := RingHom.toAlgebra f + preservesLimitsOfShape_of_natIso (tensorProdIsoPushout R S) + +/-- `Under.pushout f` preserves finite limits if `f` is flat. -/ +lemma preservesFiniteLimits_of_flat (hf : RingHom.Flat f) : + PreservesFiniteLimits (Under.pushout f) where + preservesFiniteLimits _ := + letI : Algebra R S := RingHom.toAlgebra f + haveI : Module.Flat R S := hf + preservesLimitsOfShape_of_natIso (tensorProdIsoPushout R S) + +end CommRingCat.Under diff --git a/Mathlib/Algebra/CharP/IntermediateField.lean b/Mathlib/Algebra/CharP/IntermediateField.lean index 611dc38c84f62..6016d298478c6 100644 --- a/Mathlib/Algebra/CharP/IntermediateField.lean +++ b/Mathlib/Algebra/CharP/IntermediateField.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jz Pan -/ import Mathlib.Algebra.CharP.Algebra -import Mathlib.Algebra.EuclideanDomain.Field import Mathlib.FieldTheory.IntermediateField.Basic /-! diff --git a/Mathlib/Algebra/CharP/LocalRing.lean b/Mathlib/Algebra/CharP/LocalRing.lean index e2fb6ba42ddaa..b85b347fd0fd2 100644 --- a/Mathlib/Algebra/CharP/LocalRing.lean +++ b/Mathlib/Algebra/CharP/LocalRing.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Jon Eugster. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jon Eugster -/ +import Mathlib.Algebra.CharP.Defs import Mathlib.Algebra.IsPrimePow import Mathlib.Data.Nat.Factorization.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs diff --git a/Mathlib/Algebra/CubicDiscriminant.lean b/Mathlib/Algebra/CubicDiscriminant.lean index 4104d2add1285..04cd0d3ed3474 100644 --- a/Mathlib/Algebra/CubicDiscriminant.lean +++ b/Mathlib/Algebra/CubicDiscriminant.lean @@ -468,12 +468,8 @@ def disc {R : Type*} [Ring R] (P : Cubic R) : R := theorem disc_eq_prod_three_roots (ha : P.a ≠ 0) (h3 : (map φ P).roots = {x, y, z}) : φ P.disc = (φ P.a * φ P.a * (x - y) * (x - z) * (y - z)) ^ 2 := by - simp only [disc, RingHom.map_add, RingHom.map_sub, RingHom.map_mul, map_pow] - -- Porting note: Replaced `simp only [RingHom.map_one, map_bit0, map_bit1]` with f4, f18, f27 - have f4 : φ 4 = 4 := map_natCast φ 4 - have f18 : φ 18 = 18 := map_natCast φ 18 - have f27 : φ 27 = 27 := map_natCast φ 27 - rw [f4, f18, f27, b_eq_three_roots ha h3, c_eq_three_roots ha h3, d_eq_three_roots ha h3] + simp only [disc, RingHom.map_add, RingHom.map_sub, RingHom.map_mul, map_pow, map_ofNat] + rw [b_eq_three_roots ha h3, c_eq_three_roots ha h3, d_eq_three_roots ha h3] ring1 theorem disc_ne_zero_iff_roots_ne (ha : P.a ≠ 0) (h3 : (map φ P).roots = {x, y, z}) : diff --git a/Mathlib/Algebra/DirectLimit.lean b/Mathlib/Algebra/DirectLimit.lean index af9c8c6a6689c..66ae30fb5b8fd 100644 --- a/Mathlib/Algebra/DirectLimit.lean +++ b/Mathlib/Algebra/DirectLimit.lean @@ -315,11 +315,7 @@ theorem of.zero_exact [IsDirected ι (· ≤ ·)] {i x} (H : of R ι G f i x = 0 if hx0 : x = 0 then ⟨i, le_rfl, by simp [hx0]⟩ else have hij : i ≤ j := hj _ <| by simp [DirectSum.apply_eq_component, hx0] - ⟨j, hij, by - -- Porting note: this had been - -- simpa [totalize_of_le hij] using hxj - simp only [DirectSum.toModule_lof] at hxj - rwa [totalize_of_le hij] at hxj⟩ + ⟨j, hij, by simpa [totalize, dif_pos hij, totalize_of_le hij] using hxj⟩ end DirectLimit @@ -731,8 +727,7 @@ theorem of.zero_exact_aux [Nonempty ι] [IsDirected ι (· ≤ ·)] {x : FreeCom ⟨k, ↑s ∪ t, this, isSupported_mul (isSupported_upwards hxs Set.subset_union_left) (isSupported_upwards hyt Set.subset_union_right), fun [_] => ?_⟩ - -- Porting note: RingHom.map_mul was `(restriction _).map_mul` - classical rw [RingHom.map_mul, (FreeCommRing.lift _).map_mul, ← + classical rw [(restriction _).map_mul, (FreeCommRing.lift _).map_mul, ← of.zero_exact_aux2 G f' hyt hj this hjk Set.subset_union_right, iht, (f' j k hjk).map_zero, mul_zero] diff --git a/Mathlib/Algebra/Divisibility/Basic.lean b/Mathlib/Algebra/Divisibility/Basic.lean index 7e62a5bd031dc..c51368437a942 100644 --- a/Mathlib/Algebra/Divisibility/Basic.lean +++ b/Mathlib/Algebra/Divisibility/Basic.lean @@ -5,7 +5,6 @@ Authors: Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Amelia Livingston, Neil Strickland, Aaron Anderson -/ import Mathlib.Algebra.Group.Basic -import Mathlib.Algebra.Group.Hom.Defs import Mathlib.Tactic.Common /-! @@ -83,22 +82,6 @@ alias Dvd.dvd.mul_right := dvd_mul_of_dvd_left theorem dvd_of_mul_right_dvd (h : a * b ∣ c) : a ∣ c := (dvd_mul_right a b).trans h -section map_dvd - -variable {M N : Type*} - -theorem map_dvd [Semigroup M] [Semigroup N] {F : Type*} [FunLike F M N] [MulHomClass F M N] - (f : F) {a b} : a ∣ b → f a ∣ f b - | ⟨c, h⟩ => ⟨f c, h.symm ▸ map_mul f a c⟩ - -theorem MulHom.map_dvd [Semigroup M] [Semigroup N] (f : M →ₙ* N) {a b} : a ∣ b → f a ∣ f b := - _root_.map_dvd f - -theorem MonoidHom.map_dvd [Monoid M] [Monoid N] (f : M →* N) {a b} : a ∣ b → f a ∣ f b := - _root_.map_dvd f - -end map_dvd - /-- An element `a` in a semigroup is primal if whenever `a` is a divisor of `b * c`, it can be factored as the product of a divisor of `b` and a divisor of `c`. -/ def IsPrimal (a : α) : Prop := ∀ ⦃b c⦄, a ∣ b * c → ∃ a₁ a₂, a₁ ∣ b ∧ a₂ ∣ c ∧ a = a₁ * a₂ diff --git a/Mathlib/Algebra/Divisibility/Hom.lean b/Mathlib/Algebra/Divisibility/Hom.lean new file mode 100644 index 0000000000000..36e3874d14974 --- /dev/null +++ b/Mathlib/Algebra/Divisibility/Hom.lean @@ -0,0 +1,34 @@ +/- +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, Floris van Doorn, Amelia Livingston, Yury Kudryashov, +Neil Strickland, Aaron Anderson +-/ +import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Group.Hom.Defs + +/-! +# Mapping divisibility across multiplication-preserving homomorphisms + +## Main definitions + + * `map_dvd` + +## Tags + +divisibility, divides +-/ + +attribute [local simp] mul_assoc mul_comm mul_left_comm + +variable {M N : Type*} + +theorem map_dvd [Semigroup M] [Semigroup N] {F : Type*} [FunLike F M N] [MulHomClass F M N] + (f : F) {a b} : a ∣ b → f a ∣ f b + | ⟨c, h⟩ => ⟨f c, h.symm ▸ map_mul f a c⟩ + +theorem MulHom.map_dvd [Semigroup M] [Semigroup N] (f : M →ₙ* N) {a b} : a ∣ b → f a ∣ f b := + _root_.map_dvd f + +theorem MonoidHom.map_dvd [Monoid M] [Monoid N] (f : M →* N) {a b} : a ∣ b → f a ∣ f b := + _root_.map_dvd f diff --git a/Mathlib/Algebra/Field/Subfield/Basic.lean b/Mathlib/Algebra/Field/Subfield/Basic.lean index b4b3a10a096e9..9265de24cc7bb 100644 --- a/Mathlib/Algebra/Field/Subfield/Basic.lean +++ b/Mathlib/Algebra/Field/Subfield/Basic.lean @@ -315,6 +315,7 @@ theorem closure_le {s : Set K} {t : Subfield K} : closure s ≤ t ↔ s ⊆ t := /-- Subfield closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set K⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Set.Subset.trans h subset_closure diff --git a/Mathlib/Algebra/GCDMonoid/Basic.lean b/Mathlib/Algebra/GCDMonoid/Basic.lean index 917885981d942..b6ff248ab4b41 100644 --- a/Mathlib/Algebra/GCDMonoid/Basic.lean +++ b/Mathlib/Algebra/GCDMonoid/Basic.lean @@ -1315,8 +1315,8 @@ namespace Associates variable [CancelCommMonoidWithZero α] [GCDMonoid α] instance instGCDMonoid : GCDMonoid (Associates α) where - gcd := Quotient.map₂' gcd fun _ _ (ha : Associated _ _) _ _ (hb : Associated _ _) => ha.gcd hb - lcm := Quotient.map₂' lcm fun _ _ (ha : Associated _ _) _ _ (hb : Associated _ _) => ha.lcm hb + gcd := Quotient.map₂ gcd fun _ _ (ha : Associated _ _) _ _ (hb : Associated _ _) => ha.gcd hb + lcm := Quotient.map₂ lcm fun _ _ (ha : Associated _ _) _ _ (hb : Associated _ _) => ha.lcm hb gcd_dvd_left := by rintro ⟨a⟩ ⟨b⟩; exact mk_le_mk_of_dvd (gcd_dvd_left _ _) gcd_dvd_right := by rintro ⟨a⟩ ⟨b⟩; exact mk_le_mk_of_dvd (gcd_dvd_right _ _) dvd_gcd := by diff --git a/Mathlib/Algebra/GeomSum.lean b/Mathlib/Algebra/GeomSum.lean index 7e6e9ce83070c..2a0df0564ca2b 100644 --- a/Mathlib/Algebra/GeomSum.lean +++ b/Mathlib/Algebra/GeomSum.lean @@ -346,7 +346,6 @@ protected theorem Commute.geom_sum₂_Ico_mul [Ring α] {x y : α} (h : Commute have hp := Commute.pow_pow (Commute.op h.symm) (n - 1 - k) k simpa [Commute, SemiconjBy] using hp simp only [this] - -- Porting note: gives deterministic timeout without this intermediate `have` convert (Commute.op h).mul_geom_sum₂_Ico hmn theorem geom_sum_Ico_mul [Ring α] (x : α) {m n : ℕ} (hmn : m ≤ n) : diff --git a/Mathlib/Algebra/Group/Action/Defs.lean b/Mathlib/Algebra/Group/Action/Defs.lean index 294281be04be5..fdd34cf9f6af7 100644 --- a/Mathlib/Algebra/Group/Action/Defs.lean +++ b/Mathlib/Algebra/Group/Action/Defs.lean @@ -65,7 +65,7 @@ class AddAction (G : Type*) (P : Type*) [AddMonoid G] extends VAdd G P where /-- Zero is a neutral element for `+ᵥ` -/ protected zero_vadd : ∀ p : P, (0 : G) +ᵥ p = p /-- Associativity of `+` and `+ᵥ` -/ - add_vadd : ∀ (g₁ g₂ : G) (p : P), g₁ + g₂ +ᵥ p = g₁ +ᵥ (g₂ +ᵥ p) + add_vadd : ∀ (g₁ g₂ : G) (p : P), (g₁ + g₂) +ᵥ p = g₁ +ᵥ g₂ +ᵥ p /-- Typeclass for multiplicative actions by monoids. This generalizes group actions. -/ @[to_additive (attr := ext)] @@ -140,7 +140,7 @@ instance smulCommClass_self (M α : Type*) [CommMonoid M] [MulAction M α] : SMu determined by the additive actions of `M` on `N` and `N` on `α`. -/ class VAddAssocClass (M N α : Type*) [VAdd M N] [VAdd N α] [VAdd M α] : Prop where /-- Associativity of `+ᵥ` -/ - vadd_assoc : ∀ (x : M) (y : N) (z : α), x +ᵥ y +ᵥ z = x +ᵥ (y +ᵥ z) + vadd_assoc : ∀ (x : M) (y : N) (z : α), (x +ᵥ y) +ᵥ z = x +ᵥ y +ᵥ z /-- An instance of `IsScalarTower M N α` states that the multiplicative action of `M` on `α` is determined by the multiplicative actions of `M` on `N` diff --git a/Mathlib/Algebra/Group/AddChar.lean b/Mathlib/Algebra/Group/AddChar.lean index 0279bc188d39a..e8e36fe2f414f 100644 --- a/Mathlib/Algebra/Group/AddChar.lean +++ b/Mathlib/Algebra/Group/AddChar.lean @@ -5,6 +5,8 @@ Authors: Michael Stoll -/ import Mathlib.Algebra.Ring.Regular import Mathlib.Logic.Equiv.TransferInstance +import Mathlib.Algebra.BigOperators.Pi +import Mathlib.Algebra.BigOperators.Ring /-! # Characters from additive to multiplicative monoids diff --git a/Mathlib/Algebra/Group/Graph.lean b/Mathlib/Algebra/Group/Graph.lean index a3cf4bee29867..45c759e8ff68f 100644 --- a/Mathlib/Algebra/Group/Graph.lean +++ b/Mathlib/Algebra/Group/Graph.lean @@ -163,7 +163,7 @@ set_option linter.existingAttributeWarning false in attribute [to_additive existing] coe_graph graph_toSubmonoid @[to_additive] -lemma mem_graph {f : G →* H} {x : G × H} : x ∈ f.mgraph ↔ f x.1 = x.2 := .rfl +lemma mem_graph {f : G →* H} {x : G × H} : x ∈ f.graph ↔ f x.1 = x.2 := .rfl @[to_additive] lemma graph_eq_range_prod (f : G →* H) : f.graph = range ((id _).prod f) := by aesop diff --git a/Mathlib/Algebra/Group/Indicator.lean b/Mathlib/Algebra/Group/Indicator.lean index 8dfed5c563fb9..604906c6e8770 100644 --- a/Mathlib/Algebra/Group/Indicator.lean +++ b/Mathlib/Algebra/Group/Indicator.lean @@ -120,9 +120,17 @@ set. -/ theorem mem_of_mulIndicator_ne_one (h : mulIndicator s f a ≠ 1) : a ∈ s := not_imp_comm.1 (fun hn => mulIndicator_of_not_mem hn f) h -@[to_additive] +/-- See `Set.eqOn_mulIndicator'` for the version with `sᶜ`. -/ +@[to_additive + "See `Set.eqOn_indicator'` for the version with `sᶜ`"] theorem eqOn_mulIndicator : EqOn (mulIndicator s f) f s := fun _ hx => mulIndicator_of_mem hx f +/-- See `Set.eqOn_mulIndicator` for the version with `s`. -/ +@[to_additive + "See `Set.eqOn_indicator` for the version with `s`."] +theorem eqOn_mulIndicator' : EqOn (mulIndicator s f) 1 sᶜ := + fun _ hx => mulIndicator_of_not_mem hx f + @[to_additive] theorem mulSupport_mulIndicator_subset : mulSupport (s.mulIndicator f) ⊆ s := fun _ hx => hx.imp_symm fun h => mulIndicator_of_not_mem h f diff --git a/Mathlib/Algebra/Group/Operations.lean b/Mathlib/Algebra/Group/Operations.lean index dcc6957a258a7..74d54a8784207 100644 --- a/Mathlib/Algebra/Group/Operations.lean +++ b/Mathlib/Algebra/Group/Operations.lean @@ -82,7 +82,7 @@ class SMul (M : Type u) (α : Type v) where but it is intended to be used for left actions. -/ smul : M → α → α -@[inherit_doc] infixl:65 " +ᵥ " => HVAdd.hVAdd +@[inherit_doc] infixr:65 " +ᵥ " => HVAdd.hVAdd @[inherit_doc] infixl:65 " -ᵥ " => VSub.vsub @[inherit_doc] infixr:73 " • " => HSMul.hSMul diff --git a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean index 876f75a97121b..a01f060a58f0e 100644 --- a/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Finset/Basic.lean @@ -740,11 +740,11 @@ theorem singleton_div_singleton (a b : α) : ({a} : Finset α) / {b} = {a / b} : theorem div_subset_div : s₁ ⊆ s₂ → t₁ ⊆ t₂ → s₁ / t₁ ⊆ s₂ / t₂ := image₂_subset -@[to_additive] +@[to_additive (attr := gcongr)] theorem div_subset_div_left : t₁ ⊆ t₂ → s / t₁ ⊆ s / t₂ := image₂_subset_left -@[to_additive] +@[to_additive (attr := gcongr)] theorem div_subset_div_right : s₁ ⊆ s₂ → s₁ / t ⊆ s₂ / t := image₂_subset_right @@ -958,7 +958,7 @@ protected lemma pow_right_monotone (hs : 1 ∈ s) : Monotone (s ^ ·) := pow_right_monotone <| one_subset.2 hs @[to_additive (attr := gcongr)] -lemma pow_subset_pow_left (hst : s ⊆ t) : s ^ n ⊆ t ^ n := pow_left_mono _ hst +lemma pow_subset_pow_left (hst : s ⊆ t) : s ^ n ⊆ t ^ n := subset_of_le (pow_left_mono n hst) @[to_additive (attr := gcongr)] lemma pow_subset_pow_right (hs : 1 ∈ s) (hmn : m ≤ n) : s ^ m ⊆ s ^ n := @@ -968,6 +968,10 @@ lemma pow_subset_pow_right (hs : 1 ∈ s) (hmn : m ≤ n) : s ^ m ⊆ s ^ n := lemma pow_subset_pow (hst : s ⊆ t) (ht : 1 ∈ t) (hmn : m ≤ n) : s ^ m ⊆ t ^ n := (pow_subset_pow_left hst).trans (pow_subset_pow_right ht hmn) +@[to_additive] +lemma subset_pow (hs : 1 ∈ s) (hn : n ≠ 0) : s ⊆ s ^ n := by + simpa using pow_subset_pow_right hs <| Nat.one_le_iff_ne_zero.2 hn + @[deprecated (since := "2024-11-19")] alias pow_subset_pow_of_one_mem := pow_subset_pow_right @[deprecated (since := "2024-11-19")] @@ -975,7 +979,7 @@ alias nsmul_subset_nsmul_of_zero_mem := nsmul_subset_nsmul_right @[to_additive] lemma pow_subset_pow_mul_of_sq_subset_mul (hst : s ^ 2 ⊆ t * s) (hn : n ≠ 0) : - s ^ n ⊆ t ^ (n - 1) * s := pow_le_pow_mul_of_sq_le_mul hst hn + s ^ n ⊆ t ^ (n - 1) * s := subset_of_le (pow_le_pow_mul_of_sq_le_mul hst hn) @[to_additive (attr := simp) nsmul_empty] lemma empty_pow (hn : n ≠ 0) : (∅ : Finset α) ^ n = ∅ := match n with | n + 1 => by simp [pow_succ] @@ -1468,6 +1472,8 @@ section Mul variable [Mul α] [DecidableEq α] {s t u : Finset α} {a : α} +@[to_additive] lemma smul_finset_subset_mul : a ∈ s → a • t ⊆ s * t := image_subset_image₂_right + @[to_additive] theorem op_smul_finset_subset_mul : a ∈ t → op a • s ⊆ s * t := image_subset_image₂_left @@ -1515,7 +1521,16 @@ end Semigroup section IsLeftCancelMul -variable [Mul α] [IsLeftCancelMul α] [DecidableEq α] (s t : Finset α) (a : α) +variable [Mul α] [IsLeftCancelMul α] [DecidableEq α] {s t : Finset α} {a : α} + +@[to_additive] +lemma Nontrivial.mul_left : t.Nontrivial → s.Nonempty → (s * t).Nontrivial := by + rintro ⟨a, ha, b, hb, hab⟩ ⟨c, hc⟩ + exact ⟨c * a, mul_mem_mul hc ha, c * b, mul_mem_mul hc hb, by simpa⟩ + +@[to_additive] +lemma Nontrivial.mul (hs : s.Nontrivial) (ht : t.Nontrivial) : (s * t).Nontrivial := + ht.mul_left hs.nonempty @[to_additive] theorem pairwiseDisjoint_smul_iff {s : Set α} {t : Finset α} : @@ -1523,11 +1538,11 @@ theorem pairwiseDisjoint_smul_iff {s : Set α} {t : Finset α} : simp_rw [← pairwiseDisjoint_coe, coe_smul_finset, Set.pairwiseDisjoint_smul_iff] @[to_additive (attr := simp)] -theorem card_singleton_mul : ({a} * t).card = t.card := +theorem card_singleton_mul (a : α) (t : Finset α) : ({a} * t).card = t.card := card_image₂_singleton_left _ <| mul_right_injective _ @[to_additive] -theorem singleton_mul_inter : {a} * (s ∩ t) = {a} * s ∩ ({a} * t) := +theorem singleton_mul_inter (a : α) (s t : Finset α) : {a} * (s ∩ t) = {a} * s ∩ ({a} * t) := image₂_singleton_inter _ _ <| mul_right_injective _ @[to_additive] @@ -1547,20 +1562,25 @@ theorem card_le_card_mul_self {s : Finset α} : s.card ≤ (s * s).card := by end IsLeftCancelMul -section +section IsRightCancelMul + +variable [Mul α] [IsRightCancelMul α] [DecidableEq α] {s t : Finset α} {a : α} -variable [Mul α] [IsRightCancelMul α] [DecidableEq α] (s t : Finset α) (a : α) +@[to_additive] +lemma Nontrivial.mul_right : s.Nontrivial → t.Nonempty → (s * t).Nontrivial := by + rintro ⟨a, ha, b, hb, hab⟩ ⟨c, hc⟩ + exact ⟨a * c, mul_mem_mul ha hc, b * c, mul_mem_mul hb hc, by simpa⟩ @[to_additive (attr := simp)] -theorem card_mul_singleton : (s * {a}).card = s.card := +theorem card_mul_singleton (s : Finset α) (a : α) : (s * {a}).card = s.card := card_image₂_singleton_right _ <| mul_left_injective _ @[to_additive] -theorem inter_mul_singleton : s ∩ t * {a} = s * {a} ∩ (t * {a}) := +theorem inter_mul_singleton (s t : Finset α) (a : α) : s ∩ t * {a} = s * {a} ∩ (t * {a}) := image₂_inter_singleton _ _ <| mul_left_injective _ @[to_additive] -theorem card_le_card_mul_right {t : Finset α} (ht : t.Nonempty) : s.card ≤ (s * t).card := +theorem card_le_card_mul_right (ht : t.Nonempty) : s.card ≤ (s * t).card := card_le_card_image₂_right _ ht mul_left_injective /-- @@ -1571,18 +1591,23 @@ See `card_le_card_mul_self` for the version with left-cancellative multiplicatio "The size of `s + s` is at least the size of `s`, version with right-cancellative addition. See `card_le_card_add_self` for the version with left-cancellative addition." ] -theorem card_le_card_mul_self' {s : Finset α} : s.card ≤ (s * s).card := by +theorem card_le_card_mul_self' : s.card ≤ (s * s).card := by cases s.eq_empty_or_nonempty <;> simp [card_le_card_mul_right, *] -end +end IsRightCancelMul section CancelMonoid variable [DecidableEq α] [CancelMonoid α] {s : Finset α} {m n : ℕ} +@[to_additive] +lemma Nontrivial.pow (hs : s.Nontrivial) : ∀ {n}, n ≠ 0 → (s ^ n).Nontrivial + | 1, _ => by simpa + | n + 2, _ => by simpa [pow_succ] using (hs.pow n.succ_ne_zero).mul hs + /-- See `Finset.card_pow_mono` for a version that works for the empty set. -/ @[to_additive "See `Finset.card_nsmul_mono` for a version that works for the empty set."] protected lemma Nonempty.card_pow_mono (hs : s.Nonempty) : Monotone fun n : ℕ ↦ (s ^ n).card := - monotone_nat_of_le_succ fun n ↦ by rw [pow_succ]; exact card_le_card_mul_right _ hs + monotone_nat_of_le_succ fun n ↦ by rw [pow_succ]; exact card_le_card_mul_right hs /-- See `Finset.Nonempty.card_pow_mono` for a version that works for zero powers. -/ @[to_additive "See `Finset.Nonempty.card_nsmul_mono` for a version that works for zero scalars."] diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean index 49a613a4045d4..641e71ad326f6 100644 --- a/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Basic.lean @@ -1097,6 +1097,10 @@ lemma pow_subset_pow_right (hs : 1 ∈ s) (hmn : m ≤ n) : s ^ m ⊆ s ^ n := lemma pow_subset_pow (hst : s ⊆ t) (ht : 1 ∈ t) (hmn : m ≤ n) : s ^ m ⊆ t ^ n := (pow_subset_pow_left hst).trans (pow_subset_pow_right ht hmn) +@[to_additive] +lemma subset_pow (hs : 1 ∈ s) (hn : n ≠ 0) : s ⊆ s ^ n := by + simpa using pow_subset_pow_right hs <| Nat.one_le_iff_ne_zero.2 hn + @[deprecated (since := "2024-11-19")] alias pow_subset_pow_of_one_mem := pow_subset_pow_right @[deprecated (since := "2024-11-19")] @@ -1163,6 +1167,40 @@ protected theorem _root_.IsUnit.set : IsUnit a → IsUnit ({a} : Set α) := end Monoid +section IsLeftCancelMul +variable [Mul α] [IsLeftCancelMul α] {s t : Set α} + +@[to_additive] +lemma Nontrivial.mul_left : t.Nontrivial → s.Nonempty → (s * t).Nontrivial := by + rintro ⟨a, ha, b, hb, hab⟩ ⟨c, hc⟩ + exact ⟨c * a, mul_mem_mul hc ha, c * b, mul_mem_mul hc hb, by simpa⟩ + +@[to_additive] +lemma Nontrivial.mul (hs : s.Nontrivial) (ht : t.Nontrivial) : (s * t).Nontrivial := + ht.mul_left hs.nonempty + +end IsLeftCancelMul + +section IsRightCancelMul +variable [Mul α] [IsRightCancelMul α] {s t : Set α} + +@[to_additive] +lemma Nontrivial.mul_right : s.Nontrivial → t.Nonempty → (s * t).Nontrivial := by + rintro ⟨a, ha, b, hb, hab⟩ ⟨c, hc⟩ + exact ⟨a * c, mul_mem_mul ha hc, b * c, mul_mem_mul hb hc, by simpa⟩ + +end IsRightCancelMul + +section CancelMonoid +variable [CancelMonoid α] {s t : Set α} {a : α} {n : ℕ} + +@[to_additive] +lemma Nontrivial.pow (hs : s.Nontrivial) : ∀ {n}, n ≠ 0 → (s ^ n).Nontrivial + | 1, _ => by simpa + | n + 2, _ => by simpa [pow_succ] using (hs.pow n.succ_ne_zero).mul hs + +end CancelMonoid + /-- `Set α` is a `CommMonoid` under pointwise operations if `α` is. -/ @[to_additive "`Set α` is an `AddCommMonoid` under pointwise operations if `α` is."] protected noncomputable def commMonoid [CommMonoid α] : CommMonoid (Set α) := diff --git a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean index 812782481817b..d6ccb0c30a835 100644 --- a/Mathlib/Algebra/Group/Pointwise/Set/Card.lean +++ b/Mathlib/Algebra/Group/Pointwise/Set/Card.lean @@ -62,7 +62,7 @@ attribute [deprecated natCard_inv (since := "2024-09-30")] card_inv attribute [deprecated natCard_neg (since := "2024-09-30")] card_neg @[to_additive (attr := simp)] -lemma encard_inv (s : Set G) : s⁻¹.encard = s.encard := by simp [encard, PartENat.card] +lemma encard_inv (s : Set G) : s⁻¹.encard = s.encard := by simp [encard, ENat.card] @[to_additive (attr := simp)] lemma ncard_inv (s : Set G) : s⁻¹.ncard = s.ncard := by simp [ncard] @@ -112,7 +112,7 @@ attribute [deprecated Cardinal.mk_vadd_set (since := "2024-09-30")] card_vadd_se @[to_additive (attr := simp)] lemma encard_smul_set (a : G) (s : Set α) : (a • s).encard = s.encard := by - simp [encard, PartENat.card] + simp [encard, ENat.card] @[to_additive (attr := simp)] lemma ncard_smul_set (a : G) (s : Set α) : (a • s).ncard = s.ncard := by simp [ncard] diff --git a/Mathlib/Algebra/Group/Subgroup/Basic.lean b/Mathlib/Algebra/Group/Subgroup/Basic.lean index c6b11e2b701e3..f828e651230b1 100644 --- a/Mathlib/Algebra/Group/Subgroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subgroup/Basic.lean @@ -479,6 +479,7 @@ theorem normalClosure_le_normal {N : Subgroup G} [N.Normal] (h : s ⊆ N) : norm theorem normalClosure_subset_iff {N : Subgroup G} [N.Normal] : s ⊆ N ↔ normalClosure s ≤ N := ⟨normalClosure_le_normal, Set.Subset.trans subset_normalClosure⟩ +@[gcongr] theorem normalClosure_mono {s t : Set G} (h : s ⊆ t) : normalClosure s ≤ normalClosure t := normalClosure_le_normal (Set.Subset.trans h subset_normalClosure) diff --git a/Mathlib/Algebra/Group/Subgroup/Finite.lean b/Mathlib/Algebra/Group/Subgroup/Finite.lean index 6e5342a357f4e..05d21ec805804 100644 --- a/Mathlib/Algebra/Group/Subgroup/Finite.lean +++ b/Mathlib/Algebra/Group/Subgroup/Finite.lean @@ -4,8 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kexing Ying -/ import Mathlib.Algebra.Group.Subgroup.Basic -import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Data.Finite.Card +import Mathlib.Data.Set.Finite.Range /-! # Subgroups diff --git a/Mathlib/Algebra/Group/Subgroup/Ker.lean b/Mathlib/Algebra/Group/Subgroup/Ker.lean index 5ba75d983b6b7..8fd902758f7c1 100644 --- a/Mathlib/Algebra/Group/Subgroup/Ker.lean +++ b/Mathlib/Algebra/Group/Subgroup/Ker.lean @@ -144,9 +144,15 @@ theorem range_one : (1 : G →* N).range = ⊥ := theorem _root_.Subgroup.range_subtype (H : Subgroup G) : H.subtype.range = H := SetLike.coe_injective <| (coe_range _).trans <| Subtype.range_coe -@[to_additive (attr := deprecated (since := "2024-11-26"))] +@[to_additive] alias _root_.Subgroup.subtype_range := Subgroup.range_subtype +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +attribute [deprecated Subgroup.range_subtype (since := "2024-11-26")] _root_.Subgroup.subtype_range +attribute [deprecated AddSubgroup.range_subtype (since := "2024-11-26")] +_root_.AddSubgroup.subtype_range + @[to_additive (attr := simp)] theorem _root_.Subgroup.inclusion_range {H K : Subgroup G} (h_le : H ≤ K) : (inclusion h_le).range = H.subgroupOf K := diff --git a/Mathlib/Algebra/Group/Subgroup/Lattice.lean b/Mathlib/Algebra/Group/Subgroup/Lattice.lean index ea029ac82db4b..8d9277bb28c46 100644 --- a/Mathlib/Algebra/Group/Subgroup/Lattice.lean +++ b/Mathlib/Algebra/Group/Subgroup/Lattice.lean @@ -402,7 +402,7 @@ variable {G} /-- Subgroup closure of a set is monotone in its argument: if `h ⊆ k`, then `closure h ≤ closure k`. -/ -@[to_additive +@[to_additive (attr := gcongr) "Additive subgroup closure of a set is monotone in its argument: if `h ⊆ k`, then `closure h ≤ closure k`"] theorem closure_mono ⦃h k : Set G⦄ (h' : h ⊆ k) : closure h ≤ closure k := diff --git a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean index e2c994a14d331..59e702a1824e6 100644 --- a/Mathlib/Algebra/Group/Subgroup/Pointwise.lean +++ b/Mathlib/Algebra/Group/Subgroup/Pointwise.lean @@ -50,16 +50,43 @@ lemma op_smul_coe_set [Group G] [SetLike S G] [SubgroupClass S G] {s : S} {a : G MulOpposite.op a • (s : Set G) = s := by ext; simp [Set.mem_smul_set_iff_inv_smul_mem, mul_mem_cancel_right, ha] -@[to_additive (attr := simp, norm_cast)] -lemma coe_mul_coe [SetLike S G] [DivInvMonoid G] [SubgroupClass S G] (H : S) : - H * H = (H : Set G) := by aesop (add simp mem_mul) - @[to_additive (attr := simp, norm_cast)] lemma coe_div_coe [SetLike S G] [DivisionMonoid G] [SubgroupClass S G] (H : S) : H / H = (H : Set G) := by simp [div_eq_mul_inv] variable [Group G] [AddGroup A] {s : Set G} +namespace Set + +open Subgroup + +@[to_additive (attr := simp)] +lemma mul_subgroupClosure (hs : s.Nonempty) : s * closure s = closure s := by + rw [← smul_eq_mul, ← Set.iUnion_smul_set] + have h a (ha : a ∈ s) : a • (closure s : Set G) = closure s := + smul_coe_set <| subset_closure ha + simp +contextual [h, hs] + +open scoped RightActions in +@[to_additive (attr := simp)] +lemma subgroupClosure_mul (hs : s.Nonempty) : closure s * s = closure s := by + rw [← Set.iUnion_op_smul_set] + have h a (ha : a ∈ s) : (closure s : Set G) <• a = closure s := + op_smul_coe_set <| subset_closure ha + simp +contextual [h, hs] + +@[to_additive (attr := simp)] +lemma pow_mul_subgroupClosure (hs : s.Nonempty) : ∀ n, s ^ n * closure s = closure s + | 0 => by simp + | n + 1 => by rw [pow_succ, mul_assoc, mul_subgroupClosure hs, pow_mul_subgroupClosure hs] + +@[to_additive (attr := simp)] +lemma subgroupClosure_mul_pow (hs : s.Nonempty) : ∀ n, closure s * s ^ n = closure s + | 0 => by simp + | n + 1 => by rw [pow_succ', ← mul_assoc, subgroupClosure_mul hs, subgroupClosure_mul_pow hs] + +end Set + namespace Subgroup @[to_additive (attr := simp)] @@ -175,6 +202,21 @@ theorem closure_mul_le (S T : Set G) : closure (S * T) ≤ closure S ⊔ closure (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) +@[to_additive] +lemma closure_pow_le : ∀ {n}, n ≠ 0 → closure (s ^ n) ≤ closure s + | 1, _ => by simp + | n + 2, _ => + calc + closure (s ^ (n + 2)) + _ = closure (s ^ (n + 1) * s) := by rw [pow_succ] + _ ≤ closure (s ^ (n + 1)) ⊔ closure s := closure_mul_le .. + _ ≤ closure s ⊔ closure s := by gcongr ?_ ⊔ _; exact closure_pow_le n.succ_ne_zero + _ = closure s := sup_idem _ + +@[to_additive] +lemma closure_pow {n : ℕ} (hs : 1 ∈ s) (hn : n ≠ 0) : closure (s ^ n) = closure s := + (closure_pow_le hn).antisymm <| by gcongr; exact subset_pow hs hn + @[to_additive] theorem sup_eq_closure_mul (H K : Subgroup G) : H ⊔ K = closure ((H : Set G) * (K : Set G)) := le_antisymm @@ -384,8 +426,7 @@ theorem subgroup_mul_singleton {H : Subgroup G} {h : G} (hh : h ∈ H) : (H : Se theorem singleton_mul_subgroup {H : Subgroup G} {h : G} (hh : h ∈ H) : {h} * (H : Set G) = H := by simp [preimage, mul_mem_cancel_left (inv_mem hh)] -theorem Normal.conjAct {G : Type*} [Group G] {H : Subgroup G} (hH : H.Normal) (g : ConjAct G) : - g • H = H := +theorem Normal.conjAct {H : Subgroup G} (hH : H.Normal) (g : ConjAct G) : g • H = H := have : ∀ g : ConjAct G, g • H ≤ H := fun _ => map_le_iff_le_comap.2 fun _ h => hH.conj_mem _ h _ (this g).antisymm <| (smul_inv_smul g H).symm.trans_le (map_mono <| this _) @@ -394,6 +435,15 @@ theorem Normal.conjAct {G : Type*} [Group G] {H : Subgroup G} (hH : H.Normal) (g theorem smul_normal (g : G) (H : Subgroup G) [h : Normal H] : MulAut.conj g • H = H := h.conjAct g +theorem Normal.of_conjugate_fixed {H : Subgroup G} (h : ∀ g : G, (MulAut.conj g) • H = H) : + H.Normal := by + constructor + intro n hn g + rw [← h g, Subgroup.mem_pointwise_smul_iff_inv_smul_mem, ← map_inv, MulAut.smul_def, + MulAut.conj_apply, inv_inv, mul_assoc, mul_assoc, inv_mul_cancel, mul_one, + ← mul_assoc, inv_mul_cancel, one_mul] + exact hn + theorem normalCore_eq_iInf_conjAct (H : Subgroup G) : H.normalCore = ⨅ (g : ConjAct G), g • H := by ext g @@ -545,6 +595,14 @@ theorem le_pointwise_smul_iff₀ {a : α} (ha : a ≠ 0) {S T : AddSubgroup A} : end GroupWithZero +section Semiring +variable {R M : Type*} [Semiring R] [AddCommGroup M] [Module R M] + +@[simp] protected lemma zero_smul (s : AddSubgroup M) : (0 : R) • s = ⊥ := by + simp [eq_bot_iff_forall, pointwise_smul_def] + +end Semiring + section Mul variable {R : Type*} [NonUnitalNonAssocRing R] diff --git a/Mathlib/Algebra/Group/Submonoid/Basic.lean b/Mathlib/Algebra/Group/Submonoid/Basic.lean index 04690c8d30132..db88bd856087e 100644 --- a/Mathlib/Algebra/Group/Submonoid/Basic.lean +++ b/Mathlib/Algebra/Group/Submonoid/Basic.lean @@ -138,7 +138,7 @@ theorem closure_le : closure s ≤ S ↔ s ⊆ S := /-- Submonoid closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ -@[to_additive +@[to_additive (attr := gcongr) "Additive submonoid closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`"] theorem closure_mono ⦃s t : Set M⦄ (h : s ⊆ t) : closure s ≤ closure t := diff --git a/Mathlib/Algebra/Group/Submonoid/BigOperators.lean b/Mathlib/Algebra/Group/Submonoid/BigOperators.lean new file mode 100644 index 0000000000000..5d673c2469b14 --- /dev/null +++ b/Mathlib/Algebra/Group/Submonoid/BigOperators.lean @@ -0,0 +1,141 @@ +/- +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, Kenny Lau, Johan Commelin, Mario Carneiro, Kevin Buzzard, +Amelia Livingston, Yury Kudryashov +-/ +import Mathlib.Algebra.Group.Submonoid.Defs +import Mathlib.Data.Finset.NoncommProd + +/-! +# Submonoids: membership criteria for products and sums + +In this file we prove various facts about membership in a submonoid: + +* `list_prod_mem`, `multiset_prod_mem`, `prod_mem`: if each element of a collection belongs + to a multiplicative submonoid, then so does their product; +* `list_sum_mem`, `multiset_sum_mem`, `sum_mem`: if each element of a collection belongs + to an additive submonoid, then so does their sum; + +## Tags +submonoid, submonoids +-/ + +-- We don't need ordered structures to establish basic membership facts for submonoids +assert_not_exists OrderedSemiring + +variable {M A B : Type*} + +variable [Monoid M] [SetLike B M] [SubmonoidClass B M] {S : B} + +namespace SubmonoidClass + +@[to_additive (attr := norm_cast, simp)] +theorem coe_list_prod (l : List S) : (l.prod : M) = (l.map (↑)).prod := + map_list_prod (SubmonoidClass.subtype S : _ →* M) l + +@[to_additive (attr := norm_cast, simp)] +theorem coe_multiset_prod {M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (m : Multiset S) : + (m.prod : M) = (m.map (↑)).prod := + (SubmonoidClass.subtype S : _ →* M).map_multiset_prod m + +@[to_additive (attr := norm_cast, simp)] +theorem coe_finset_prod {ι M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (f : ι → S) + (s : Finset ι) : ↑(∏ i ∈ s, f i) = (∏ i ∈ s, f i : M) := + map_prod (SubmonoidClass.subtype S) f s + +end SubmonoidClass + +open SubmonoidClass + +/-- Product of a list of elements in a submonoid is in the submonoid. -/ +@[to_additive "Sum of a list of elements in an `AddSubmonoid` is in the `AddSubmonoid`."] +theorem list_prod_mem {l : List M} (hl : ∀ x ∈ l, x ∈ S) : l.prod ∈ S := by + lift l to List S using hl + rw [← coe_list_prod] + exact l.prod.coe_prop + +/-- Product of a multiset of elements in a submonoid of a `CommMonoid` is in the submonoid. -/ +@[to_additive + "Sum of a multiset of elements in an `AddSubmonoid` of an `AddCommMonoid` is + in the `AddSubmonoid`."] +theorem multiset_prod_mem {M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (m : Multiset M) + (hm : ∀ a ∈ m, a ∈ S) : m.prod ∈ S := by + lift m to Multiset S using hm + rw [← coe_multiset_prod] + exact m.prod.coe_prop + +/-- Product of elements of a submonoid of a `CommMonoid` indexed by a `Finset` is in the + submonoid. -/ +@[to_additive + "Sum of elements in an `AddSubmonoid` of an `AddCommMonoid` indexed by a `Finset` + is in the `AddSubmonoid`."] +theorem prod_mem {M : Type*} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] {ι : Type*} + {t : Finset ι} {f : ι → M} (h : ∀ c ∈ t, f c ∈ S) : (∏ c ∈ t, f c) ∈ S := + multiset_prod_mem (t.1.map f) fun _x hx => + let ⟨i, hi, hix⟩ := Multiset.mem_map.1 hx + hix ▸ h i hi + +namespace Submonoid + +variable (s : Submonoid M) + +@[to_additive (attr := norm_cast)] +theorem coe_list_prod (l : List s) : (l.prod : M) = (l.map (↑)).prod := + map_list_prod s.subtype l + +@[to_additive (attr := norm_cast)] +theorem coe_multiset_prod {M} [CommMonoid M] (S : Submonoid M) (m : Multiset S) : + (m.prod : M) = (m.map (↑)).prod := + S.subtype.map_multiset_prod m + +@[to_additive (attr := norm_cast)] +theorem coe_finset_prod {ι M} [CommMonoid M] (S : Submonoid M) (f : ι → S) (s : Finset ι) : + ↑(∏ i ∈ s, f i) = (∏ i ∈ s, f i : M) := + map_prod S.subtype f s + +/-- Product of a list of elements in a submonoid is in the submonoid. -/ +@[to_additive "Sum of a list of elements in an `AddSubmonoid` is in the `AddSubmonoid`."] +theorem list_prod_mem {l : List M} (hl : ∀ x ∈ l, x ∈ s) : l.prod ∈ s := by + lift l to List s using hl + rw [← coe_list_prod] + exact l.prod.coe_prop + +/-- Product of a multiset of elements in a submonoid of a `CommMonoid` is in the submonoid. -/ +@[to_additive + "Sum of a multiset of elements in an `AddSubmonoid` of an `AddCommMonoid` is + in the `AddSubmonoid`."] +theorem multiset_prod_mem {M} [CommMonoid M] (S : Submonoid M) (m : Multiset M) + (hm : ∀ a ∈ m, a ∈ S) : m.prod ∈ S := by + lift m to Multiset S using hm + rw [← coe_multiset_prod] + exact m.prod.coe_prop + +@[to_additive] +theorem multiset_noncommProd_mem (S : Submonoid M) (m : Multiset M) (comm) (h : ∀ x ∈ m, x ∈ S) : + m.noncommProd comm ∈ S := by + induction m using Quotient.inductionOn with | h l => ?_ + simp only [Multiset.quot_mk_to_coe, Multiset.noncommProd_coe] + exact Submonoid.list_prod_mem _ h + +/-- Product of elements of a submonoid of a `CommMonoid` indexed by a `Finset` is in the + submonoid. -/ +@[to_additive + "Sum of elements in an `AddSubmonoid` of an `AddCommMonoid` indexed by a `Finset` + is in the `AddSubmonoid`."] +theorem prod_mem {M : Type*} [CommMonoid M] (S : Submonoid M) {ι : Type*} {t : Finset ι} + {f : ι → M} (h : ∀ c ∈ t, f c ∈ S) : (∏ c ∈ t, f c) ∈ S := + S.multiset_prod_mem (t.1.map f) fun _ hx => + let ⟨i, hi, hix⟩ := Multiset.mem_map.1 hx + hix ▸ h i hi + +@[to_additive] +theorem noncommProd_mem (S : Submonoid M) {ι : Type*} (t : Finset ι) (f : ι → M) (comm) + (h : ∀ c ∈ t, f c ∈ S) : t.noncommProd f comm ∈ S := by + apply multiset_noncommProd_mem + intro y + rw [Multiset.mem_map] + rintro ⟨x, ⟨hx, rfl⟩⟩ + exact h x hx + +end Submonoid diff --git a/Mathlib/Algebra/Group/Submonoid/Membership.lean b/Mathlib/Algebra/Group/Submonoid/Membership.lean index 2eeb9e1f37c14..82f50808f2140 100644 --- a/Mathlib/Algebra/Group/Submonoid/Membership.lean +++ b/Mathlib/Algebra/Group/Submonoid/Membership.lean @@ -10,19 +10,14 @@ import Mathlib.Algebra.Group.Submonoid.Operations import Mathlib.Algebra.GroupWithZero.Divisibility import Mathlib.Algebra.Ring.Idempotents import Mathlib.Algebra.Ring.Int.Defs -import Mathlib.Data.Finset.NoncommProd +import Mathlib.Data.Fintype.Card import Mathlib.Data.Nat.Cast.Basic -import Mathlib.Util.AssertExists /-! # Submonoids: membership criteria In this file we prove various facts about membership in a submonoid: -* `list_prod_mem`, `multiset_prod_mem`, `prod_mem`: if each element of a collection belongs - to a multiplicative submonoid, then so does their product; -* `list_sum_mem`, `multiset_sum_mem`, `sum_mem`: if each element of a collection belongs - to an additive submonoid, then so does their sum; * `pow_mem`, `nsmul_mem`: if `x ∈ S` where `S` is a multiplicative (resp., additive) submonoid and `n` is a natural number, then `x^n` (resp., `n • x`) belongs to `S`; * `mem_iSup_of_directed`, `coe_iSup_of_directed`, `mem_sSup_of_directedOn`, @@ -46,118 +41,6 @@ section Assoc variable [Monoid M] [SetLike B M] [SubmonoidClass B M] {S : B} -namespace SubmonoidClass - -@[to_additive (attr := norm_cast, simp)] -theorem coe_list_prod (l : List S) : (l.prod : M) = (l.map (↑)).prod := - map_list_prod (SubmonoidClass.subtype S : _ →* M) l - -@[to_additive (attr := norm_cast, simp)] -theorem coe_multiset_prod {M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (m : Multiset S) : - (m.prod : M) = (m.map (↑)).prod := - (SubmonoidClass.subtype S : _ →* M).map_multiset_prod m - -@[to_additive (attr := norm_cast, simp)] -theorem coe_finset_prod {ι M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (f : ι → S) - (s : Finset ι) : ↑(∏ i ∈ s, f i) = (∏ i ∈ s, f i : M) := - map_prod (SubmonoidClass.subtype S) f s - -end SubmonoidClass - -open SubmonoidClass - -/-- Product of a list of elements in a submonoid is in the submonoid. -/ -@[to_additive "Sum of a list of elements in an `AddSubmonoid` is in the `AddSubmonoid`."] -theorem list_prod_mem {l : List M} (hl : ∀ x ∈ l, x ∈ S) : l.prod ∈ S := by - lift l to List S using hl - rw [← coe_list_prod] - exact l.prod.coe_prop - -/-- Product of a multiset of elements in a submonoid of a `CommMonoid` is in the submonoid. -/ -@[to_additive - "Sum of a multiset of elements in an `AddSubmonoid` of an `AddCommMonoid` is - in the `AddSubmonoid`."] -theorem multiset_prod_mem {M} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] (m : Multiset M) - (hm : ∀ a ∈ m, a ∈ S) : m.prod ∈ S := by - lift m to Multiset S using hm - rw [← coe_multiset_prod] - exact m.prod.coe_prop - -/-- Product of elements of a submonoid of a `CommMonoid` indexed by a `Finset` is in the - submonoid. -/ -@[to_additive - "Sum of elements in an `AddSubmonoid` of an `AddCommMonoid` indexed by a `Finset` - is in the `AddSubmonoid`."] -theorem prod_mem {M : Type*} [CommMonoid M] [SetLike B M] [SubmonoidClass B M] {ι : Type*} - {t : Finset ι} {f : ι → M} (h : ∀ c ∈ t, f c ∈ S) : (∏ c ∈ t, f c) ∈ S := - multiset_prod_mem (t.1.map f) fun _x hx => - let ⟨i, hi, hix⟩ := Multiset.mem_map.1 hx - hix ▸ h i hi - -namespace Submonoid - -variable (s : Submonoid M) - -@[to_additive (attr := norm_cast)] -theorem coe_list_prod (l : List s) : (l.prod : M) = (l.map (↑)).prod := - map_list_prod s.subtype l - -@[to_additive (attr := norm_cast)] -theorem coe_multiset_prod {M} [CommMonoid M] (S : Submonoid M) (m : Multiset S) : - (m.prod : M) = (m.map (↑)).prod := - S.subtype.map_multiset_prod m - -@[to_additive (attr := norm_cast)] -theorem coe_finset_prod {ι M} [CommMonoid M] (S : Submonoid M) (f : ι → S) (s : Finset ι) : - ↑(∏ i ∈ s, f i) = (∏ i ∈ s, f i : M) := - map_prod S.subtype f s - -/-- Product of a list of elements in a submonoid is in the submonoid. -/ -@[to_additive "Sum of a list of elements in an `AddSubmonoid` is in the `AddSubmonoid`."] -theorem list_prod_mem {l : List M} (hl : ∀ x ∈ l, x ∈ s) : l.prod ∈ s := by - lift l to List s using hl - rw [← coe_list_prod] - exact l.prod.coe_prop - -/-- Product of a multiset of elements in a submonoid of a `CommMonoid` is in the submonoid. -/ -@[to_additive - "Sum of a multiset of elements in an `AddSubmonoid` of an `AddCommMonoid` is - in the `AddSubmonoid`."] -theorem multiset_prod_mem {M} [CommMonoid M] (S : Submonoid M) (m : Multiset M) - (hm : ∀ a ∈ m, a ∈ S) : m.prod ∈ S := by - lift m to Multiset S using hm - rw [← coe_multiset_prod] - exact m.prod.coe_prop - -@[to_additive] -theorem multiset_noncommProd_mem (S : Submonoid M) (m : Multiset M) (comm) (h : ∀ x ∈ m, x ∈ S) : - m.noncommProd comm ∈ S := by - induction m using Quotient.inductionOn with | h l => ?_ - simp only [Multiset.quot_mk_to_coe, Multiset.noncommProd_coe] - exact Submonoid.list_prod_mem _ h - -/-- Product of elements of a submonoid of a `CommMonoid` indexed by a `Finset` is in the - submonoid. -/ -@[to_additive - "Sum of elements in an `AddSubmonoid` of an `AddCommMonoid` indexed by a `Finset` - is in the `AddSubmonoid`."] -theorem prod_mem {M : Type*} [CommMonoid M] (S : Submonoid M) {ι : Type*} {t : Finset ι} - {f : ι → M} (h : ∀ c ∈ t, f c ∈ S) : (∏ c ∈ t, f c) ∈ S := - S.multiset_prod_mem (t.1.map f) fun _ hx => - let ⟨i, hi, hix⟩ := Multiset.mem_map.1 hx - hix ▸ h i hi - -@[to_additive] -theorem noncommProd_mem (S : Submonoid M) {ι : Type*} (t : Finset ι) (f : ι → M) (comm) - (h : ∀ c ∈ t, f c ∈ S) : t.noncommProd f comm ∈ S := by - apply multiset_noncommProd_mem - intro y - rw [Multiset.mem_map] - rintro ⟨x, ⟨hx, rfl⟩⟩ - exact h x hx - -end Submonoid - end Assoc section NonAssoc diff --git a/Mathlib/Algebra/Group/Submonoid/Operations.lean b/Mathlib/Algebra/Group/Submonoid/Operations.lean index 86c4066e007df..a643434cac8a2 100644 --- a/Mathlib/Algebra/Group/Submonoid/Operations.lean +++ b/Mathlib/Algebra/Group/Submonoid/Operations.lean @@ -870,7 +870,13 @@ def inclusion {S T : Submonoid M} (h : S ≤ T) : S →* T := theorem mrange_subtype (s : Submonoid M) : mrange s.subtype = s := SetLike.coe_injective <| (coe_mrange _).trans <| Subtype.range_coe -@[to_additive (attr := deprecated (since := "2024-11-25"))] alias range_subtype := mrange_subtype +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +@[to_additive] alias range_subtype := mrange_subtype +attribute [deprecated mrange_subtype (since := "2024-11-25")] range_subtype +attribute [deprecated AddSubmonoid.mrange_subtype (since := "2024-11-25")] +AddSubmonoid.range_subtype + @[to_additive] theorem eq_top_iff' : S = ⊤ ↔ ∀ x : M, x ∈ S := diff --git a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean index 9c5e50a98eb6b..567936d4f37ef 100644 --- a/Mathlib/Algebra/Group/Submonoid/Pointwise.lean +++ b/Mathlib/Algebra/Group/Submonoid/Pointwise.lean @@ -54,9 +54,20 @@ way to `Module`). open Set Pointwise -variable {α : Type*} {G : Type*} {M : Type*} {R : Type*} {A : Type*} +variable {α G M R A S : Type*} variable [Monoid M] [AddMonoid A] +@[to_additive (attr := simp, norm_cast)] +lemma coe_mul_coe [SetLike S M] [SubmonoidClass S M] (H : S) : H * H = (H : Set M) := by + aesop (add simp mem_mul) + +set_option linter.unusedVariables false in +@[to_additive (attr := simp)] +lemma coe_set_pow [SetLike S M] [SubmonoidClass S M] : + ∀ {n} (hn : n ≠ 0) (H : S), (H ^ n : Set M) = H + | 1, _, H => by simp + | n + 2, _, H => by rw [pow_succ, coe_set_pow n.succ_ne_zero, coe_mul_coe] + /-! Some lemmas about pointwise multiplication and submonoids. Ideally we put these in `GroupTheory.Submonoid.Basic`, but currently we cannot because that file is imported by this. -/ @@ -85,6 +96,21 @@ theorem closure_mul_le (S T : Set M) : closure (S * T) ≤ closure S ⊔ closure (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) +@[to_additive] +lemma closure_pow_le : ∀ {n}, n ≠ 0 → closure (s ^ n) ≤ closure s + | 1, _ => by simp + | n + 2, _ => + calc + closure (s ^ (n + 2)) + _ = closure (s ^ (n + 1) * s) := by rw [pow_succ] + _ ≤ closure (s ^ (n + 1)) ⊔ closure s := closure_mul_le .. + _ ≤ closure s ⊔ closure s := by gcongr ?_ ⊔ _; exact closure_pow_le n.succ_ne_zero + _ = closure s := sup_idem _ + +@[to_additive] +lemma closure_pow {n : ℕ} (hs : 1 ∈ s) (hn : n ≠ 0) : closure (s ^ n) = closure s := + (closure_pow_le hn).antisymm <| by gcongr; exact subset_pow hs hn + @[to_additive] theorem sup_eq_closure_mul (H K : Submonoid M) : H ⊔ K = closure ((H : Set M) * (K : Set M)) := le_antisymm @@ -561,15 +587,10 @@ theorem bot_mul (S : AddSubmonoid R) : ⊥ * S = ⊥ := variable {M N P Q : AddSubmonoid R} -@[mono] -theorem mul_le_mul (hmp : M ≤ P) (hnq : N ≤ Q) : M * N ≤ P * Q := - smul_le_smul hmp hnq - -theorem mul_le_mul_left (h : M ≤ N) : M * P ≤ N * P := - smul_le_smul_left h +@[mono, gcongr] lemma mul_le_mul (hmp : M ≤ P) (hnq : N ≤ Q) : M * N ≤ P * Q := smul_le_smul hmp hnq -theorem mul_le_mul_right (h : N ≤ P) : M * N ≤ M * P := - smul_le_smul_right h +@[gcongr] lemma mul_le_mul_left (h : M ≤ N) : M * P ≤ N * P := smul_le_smul_left h +@[gcongr] lemma mul_le_mul_right (h : N ≤ P) : M * N ≤ M * P := smul_le_smul_right h theorem mul_subset_mul : (↑M : Set R) * (↑N : Set R) ⊆ (↑(M * N) : Set R) := smul_subset_smul diff --git a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean index 72a594ef2bd7a..aafb3813bc835 100644 --- a/Mathlib/Algebra/Group/Subsemigroup/Basic.lean +++ b/Mathlib/Algebra/Group/Subsemigroup/Basic.lean @@ -124,8 +124,8 @@ theorem closure_le : closure s ≤ S ↔ s ⊆ S := /-- subsemigroup closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ -@[to_additive "Additive subsemigroup closure of a set is monotone in its argument: if `s ⊆ t`, - then `closure s ≤ closure t`"] +@[to_additive (attr := gcongr) "Additive subsemigroup closure of a set is monotone in its argument: +if `s ⊆ t`, then `closure s ≤ closure t`"] theorem closure_mono ⦃s t : Set M⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Subset.trans h subset_closure diff --git a/Mathlib/Algebra/Group/Units/Hom.lean b/Mathlib/Algebra/Group/Units/Hom.lean index f82c97cddb10c..a2c7a435b6886 100644 --- a/Mathlib/Algebra/Group/Units/Hom.lean +++ b/Mathlib/Algebra/Group/Units/Hom.lean @@ -79,6 +79,11 @@ theorem coe_map (f : M →* N) (x : Mˣ) : ↑(map f x) = f x := rfl @[to_additive (attr := simp)] theorem coe_map_inv (f : M →* N) (u : Mˣ) : ↑(map f u)⁻¹ = f ↑u⁻¹ := rfl +@[to_additive (attr := simp)] +lemma map_mk (f : M →* N) (val inv : M) (val_inv inv_val) : + map f (mk val inv val_inv inv_val) = mk (f val) (f inv) + (by rw [← f.map_mul, val_inv, f.map_one]) (by rw [← f.map_mul, inv_val, f.map_one]) := rfl + @[to_additive (attr := simp)] theorem map_comp (f : M →* N) (g : N →* P) : map (g.comp f) = (map g).comp (map f) := rfl diff --git a/Mathlib/Algebra/GroupWithZero/InjSurj.lean b/Mathlib/Algebra/GroupWithZero/InjSurj.lean index 75dc801b0bbb6..fb65d3fb24e9c 100644 --- a/Mathlib/Algebra/GroupWithZero/InjSurj.lean +++ b/Mathlib/Algebra/GroupWithZero/InjSurj.lean @@ -51,25 +51,30 @@ variable [Mul M₀] [Zero M₀] [Mul M₀'] [Zero M₀'] include hf zero mul /-- Pull back a `NoZeroDivisors` instance along an injective function. -/ -protected theorem Function.Injective.noZeroDivisors [NoZeroDivisors M₀'] : NoZeroDivisors M₀ := - { eq_zero_or_eq_zero_of_mul_eq_zero := fun {a b} H ↦ - have : f a * f b = 0 := by rw [← mul, H, zero] - (eq_zero_or_eq_zero_of_mul_eq_zero this).imp - (fun H => hf <| by rwa [zero]) fun H => hf <| by rwa [zero] } +protected theorem Function.Injective.noZeroDivisors [NoZeroDivisors M₀'] : NoZeroDivisors M₀ where + eq_zero_or_eq_zero_of_mul_eq_zero {a b} H := + have : f a * f b = 0 := by rw [← mul, H, zero] + (eq_zero_or_eq_zero_of_mul_eq_zero this).imp + (fun H ↦ hf <| by rwa [zero]) fun H ↦ hf <| by rwa [zero] protected theorem Function.Injective.isLeftCancelMulZero - [IsLeftCancelMulZero M₀'] : IsLeftCancelMulZero M₀ := - { mul_left_cancel_of_ne_zero := fun Hne He => by - have := congr_arg f He - rw [mul, mul] at this - exact hf (mul_left_cancel₀ (fun Hfa => Hne <| hf <| by rw [Hfa, zero]) this) } + [IsLeftCancelMulZero M₀'] : IsLeftCancelMulZero M₀ where + mul_left_cancel_of_ne_zero Hne He := by + have := congr_arg f He + rw [mul, mul] at this + exact hf (mul_left_cancel₀ (fun Hfa => Hne <| hf <| by rw [Hfa, zero]) this) protected theorem Function.Injective.isRightCancelMulZero - [IsRightCancelMulZero M₀'] : IsRightCancelMulZero M₀ := - { mul_right_cancel_of_ne_zero := fun Hne He => by - have := congr_arg f He - rw [mul, mul] at this - exact hf (mul_right_cancel₀ (fun Hfa => Hne <| hf <| by rw [Hfa, zero]) this) } + [IsRightCancelMulZero M₀'] : IsRightCancelMulZero M₀ where + mul_right_cancel_of_ne_zero Hne He := by + have := congr_arg f He + rw [mul, mul] at this + exact hf (mul_right_cancel₀ (fun Hfa => Hne <| hf <| by rw [Hfa, zero]) this) + +protected theorem Function.Injective.isCancelMulZero + [IsCancelMulZero M₀'] : IsCancelMulZero M₀ where + __ := hf.isLeftCancelMulZero f zero mul + __ := hf.isRightCancelMulZero f zero mul end NoZeroDivisors @@ -192,7 +197,7 @@ protected abbrev Function.Injective.groupWithZero [Zero G₀'] [Mul G₀'] [One (zpow : ∀ (x) (n : ℤ), f (x ^ n) = f x ^ n) : GroupWithZero G₀' := { hf.monoidWithZero f zero one mul npow, hf.divInvMonoid f one mul inv div npow zpow, - pullback_nonzero f zero one with + domain_nontrivial f zero one with inv_zero := hf <| by rw [inv, zero, inv_zero], mul_inv_cancel := fun x hx => hf <| by rw [one, mul, inv, mul_inv_cancel₀ ((hf.ne_iff' zero).2 hx)] } diff --git a/Mathlib/Algebra/GroupWithZero/NeZero.lean b/Mathlib/Algebra/GroupWithZero/NeZero.lean index 5f9e303a359d3..0d8a9a7bdb064 100644 --- a/Mathlib/Algebra/GroupWithZero/NeZero.lean +++ b/Mathlib/Algebra/GroupWithZero/NeZero.lean @@ -31,12 +31,14 @@ instance NeZero.one : NeZero (1 : M₀) := ⟨by _ = y := by rw [one_mul]⟩ /-- Pullback a `Nontrivial` instance along a function sending `0` to `0` and `1` to `1`. -/ -theorem pullback_nonzero [Zero M₀'] [One M₀'] (f : M₀' → M₀) (zero : f 0 = 0) (one : f 1 = 1) : +theorem domain_nontrivial [Zero M₀'] [One M₀'] (f : M₀' → M₀) (zero : f 0 = 0) (one : f 1 = 1) : Nontrivial M₀' := ⟨⟨0, 1, mt (congr_arg f) <| by rw [zero, one] exact zero_ne_one⟩⟩ +@[deprecated (since := "2024-12-07")] alias pullback_nonzero := domain_nontrivial + section GroupWithZero variable {G₀ : Type*} [GroupWithZero G₀] {a : G₀} diff --git a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean index e1c973a0dcb5f..1cae6fca2dc4b 100644 --- a/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean +++ b/Mathlib/Algebra/GroupWithZero/NonZeroDivisors.lean @@ -105,10 +105,9 @@ def nonZeroSMulDivisors (R : Type*) [MonoidWithZero R] (M : Type _) [Zero M] [Mu /-- The notation for the submonoid of non-zero smul-divisors. -/ scoped[nonZeroSMulDivisors] notation:9000 R "⁰[" M "]" => nonZeroSMulDivisors R M -section nonZeroDivisors - open nonZeroDivisors +section MonoidWithZero variable {M M' M₁ R R' F : Type*} [MonoidWithZero M] [MonoidWithZero M'] [CommMonoidWithZero M₁] [Ring R] [CommRing R'] @@ -180,11 +179,6 @@ theorem mul_mem_nonZeroDivisors {a b : M₁} : a * b ∈ M₁⁰ ↔ a ∈ M₁ apply hb rw [mul_assoc, hx] -theorem isUnit_of_mem_nonZeroDivisors {G₀ : Type*} [GroupWithZero G₀] {x : G₀} - (hx : x ∈ nonZeroDivisors G₀) : IsUnit x := - ⟨⟨x, x⁻¹, mul_inv_cancel₀ (nonZeroDivisors.ne_zero hx), - inv_mul_cancel₀ (nonZeroDivisors.ne_zero hx)⟩, rfl⟩ - lemma IsUnit.mem_nonZeroDivisors {a : M} (ha : IsUnit a) : a ∈ M⁰ := fun _ h ↦ ha.mul_left_eq_zero.mp h @@ -199,7 +193,7 @@ theorem eq_zero_of_ne_zero_of_mul_left_eq_zero [NoZeroDivisors M] {x y : M} (hnx theorem mem_nonZeroDivisors_of_ne_zero [NoZeroDivisors M] {x : M} (hx : x ≠ 0) : x ∈ M⁰ := fun _ ↦ eq_zero_of_ne_zero_of_mul_right_eq_zero hx -theorem mem_nonZeroDivisors_iff_ne_zero [NoZeroDivisors M] [Nontrivial M] {x : M} : +@[simp] lemma mem_nonZeroDivisors_iff_ne_zero [NoZeroDivisors M] [Nontrivial M] {x : M} : x ∈ M⁰ ↔ x ≠ 0 := ⟨nonZeroDivisors.ne_zero, mem_nonZeroDivisors_of_ne_zero⟩ variable [FunLike F M M'] @@ -252,7 +246,24 @@ lemma isUnit_iff_mem_nonZeroDivisors_of_finite [Finite R] {a : R} : rw [← sub_eq_zero, ← sub_mul] at hbc exact sub_eq_zero.mp (ha _ hbc) -end nonZeroDivisors +end MonoidWithZero + +section GroupWithZero +variable {G₀ : Type*} [GroupWithZero G₀] {x : G₀} + +/-- Canonical isomorphism between the non-zero-divisors and units of a group with zero. -/ +@[simps] +noncomputable def nonZeroDivisorsEquivUnits : G₀⁰ ≃* G₀ˣ where + toFun u := .mk0 _ <| mem_nonZeroDivisors_iff_ne_zero.1 u.2 + invFun u := ⟨u, u.isUnit.mem_nonZeroDivisors⟩ + left_inv u := rfl + right_inv u := by simp + map_mul' u v := by simp + +lemma isUnit_of_mem_nonZeroDivisors (hx : x ∈ nonZeroDivisors G₀) : IsUnit x := + (nonZeroDivisorsEquivUnits ⟨x, hx⟩).isUnit + +end GroupWithZero section nonZeroSMulDivisors diff --git a/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean b/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean index c112e0a96c541..0de5a19d7fbc0 100644 --- a/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean +++ b/Mathlib/Algebra/GroupWithZero/Pointwise/Finset.lean @@ -185,12 +185,18 @@ open scoped RightActions @[simp] lemma inv_smul_finset_distrib₀ (a : α) (s : Finset α) : (a • s)⁻¹ = s⁻¹ <• a⁻¹ := by obtain rfl | ha := eq_or_ne a 0 · obtain rfl | hs := s.eq_empty_or_nonempty <;> simp [*] - · ext; simp [← inv_smul_mem_iff₀, *] + -- was `simp` and very slow (https://github.com/leanprover-community/mathlib4/issues/19751) + · ext; simp only [mem_inv', ne_eq, not_false_eq_true, ← inv_smul_mem_iff₀, smul_eq_mul, + MulOpposite.op_inv, inv_eq_zero, MulOpposite.op_eq_zero_iff, inv_inv, + MulOpposite.smul_eq_mul_unop, MulOpposite.unop_op, mul_inv_rev, ha] @[simp] lemma inv_op_smul_finset_distrib₀ (a : α) (s : Finset α) : (s <• a)⁻¹ = 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₀, *] + -- was `simp` and very slow (https://github.com/leanprover-community/mathlib4/issues/19751) + · ext; simp only [mem_inv', ne_eq, MulOpposite.op_eq_zero_iff, not_false_eq_true, ← + inv_smul_mem_iff₀, MulOpposite.smul_eq_mul_unop, MulOpposite.unop_inv, MulOpposite.unop_op, + inv_eq_zero, inv_inv, smul_eq_mul, mul_inv_rev, ha] end GroupWithZero diff --git a/Mathlib/Algebra/GroupWithZero/Units/Equiv.lean b/Mathlib/Algebra/GroupWithZero/Units/Equiv.lean index c93d58a0a6142..2d7511f6ec174 100644 --- a/Mathlib/Algebra/GroupWithZero/Units/Equiv.lean +++ b/Mathlib/Algebra/GroupWithZero/Units/Equiv.lean @@ -12,18 +12,20 @@ import Mathlib.Algebra.GroupWithZero.Units.Basic assert_not_exists DenselyOrdered -variable {G₀ : Type*} [GroupWithZero G₀] +variable {G₀ : Type*} + +namespace Equiv +section GroupWithZero +variable [GroupWithZero G₀] /-- In a `GroupWithZero` `G₀`, the unit group `G₀ˣ` is equivalent to the subtype of nonzero elements. -/ -@[simps] def unitsEquivNeZero : G₀ˣ ≃ {a : G₀ // a ≠ 0} where +@[simps] def _root_.unitsEquivNeZero : G₀ˣ ≃ {a : G₀ // a ≠ 0} where toFun a := ⟨a, a.ne_zero⟩ invFun a := Units.mk0 _ a.prop left_inv _ := Units.ext rfl right_inv _ := rfl -namespace Equiv - /-- Left multiplication by a nonzero element in a `GroupWithZero` is a permutation of the underlying type. -/ @[simps! (config := .asFn)] @@ -45,10 +47,25 @@ theorem _root_.mulRight_bijective₀ (a : G₀) (ha : a ≠ 0) : Function.Biject /-- Right division by a nonzero element in a `GroupWithZero` is a permutation of the underlying type. -/ @[simps! (config := { simpRhs := true })] -def divRight₀ (a : G₀) (ha : a ≠ 0) : G₀ ≃ G₀ where +def divRight₀ (a : G₀) (ha : a ≠ 0) : Perm G₀ where toFun := (· / a) invFun := (· * a) left_inv _ := by simp [ha] right_inv _ := by simp [ha] +end GroupWithZero + +section CommGroupWithZero +variable [CommGroupWithZero G₀] + +/-- Left division by a nonzero element in a `CommGroupWithZero` is a permutation of the underlying +type. -/ +@[simps! (config := { simpRhs := true })] +def divLeft₀ (a : G₀) (ha : a ≠ 0) : Perm G₀ where + toFun := (a / ·) + invFun := (a / ·) + left_inv _ := by simp [ha] + right_inv _ := by simp [ha] + +end CommGroupWithZero end Equiv diff --git a/Mathlib/Algebra/Homology/BifunctorAssociator.lean b/Mathlib/Algebra/Homology/BifunctorAssociator.lean index 3edcc3044b554..e7935213a0d90 100644 --- a/Mathlib/Algebra/Homology/BifunctorAssociator.lean +++ b/Mathlib/Algebra/Homology/BifunctorAssociator.lean @@ -341,8 +341,8 @@ lemma d_eq (j j' : ι₄) [HasGoodTrifunctor₁₂Obj F₁₂ G K₁ K₂ K₃ c by_cases h₁ : c₁₂.Rel i₁₂ (c₁₂.next i₁₂) · by_cases h₂ : ComplexShape.π c₁₂ c₃ c₄ (c₁₂.next i₁₂, i₃) = j' · rw [mapBifunctor.d₁_eq _ _ _ _ h₁ _ _ h₂] - simp only [mapBifunctor.d_eq, Functor.map_add, NatTrans.app_add, Preadditive.add_comp, - smul_add, Preadditive.comp_add, Linear.comp_units_smul] + simp only [i₁₂, mapBifunctor.d_eq, Functor.map_add, NatTrans.app_add, + Preadditive.add_comp, smul_add, Preadditive.comp_add, Linear.comp_units_smul] congr 1 · rw [← NatTrans.comp_app_assoc, ← Functor.map_comp, mapBifunctor.ι_D₁] @@ -701,7 +701,8 @@ lemma d_eq : · rw [d₃_eq_zero] intro h₂ apply h₁ - simpa only [ComplexShape.next_π₂ c₂ c₂₃ i₂ h₂] using ComplexShape.rel_π₂ c₂ c₂₃ i₂ h₂ + simpa only [i₂₃, ComplexShape.next_π₂ c₂ c₂₃ i₂ h₂] + using ComplexShape.rel_π₂ c₂ c₂₃ i₂ h₂ end mapBifunctor₂₃ diff --git a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean index b5130066b0f40..7a3a1921a4ba1 100644 --- a/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean +++ b/Mathlib/Algebra/Homology/DerivedCategory/Ext/Basic.lean @@ -206,33 +206,33 @@ private lemma zero_hom' : (0 : Ext X Y n).hom' = 0 := @[simp] lemma add_comp (α₁ α₂ : Ext X Y n) {m : ℕ} (β : Ext Y Z m) {p : ℕ} (h : n + m = p) : (α₁ + α₂).comp β h = α₁.comp β h + α₂.comp β h := by - letI := HasDerivedCategory.standard C; ext; simp [add_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, add_hom'] @[simp] lemma comp_add (α : Ext X Y n) {m : ℕ} (β₁ β₂ : Ext Y Z m) {p : ℕ} (h : n + m = p) : α.comp (β₁ + β₂) h = α.comp β₁ h + α.comp β₂ h := by - letI := HasDerivedCategory.standard C; ext; simp [add_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, add_hom'] @[simp] lemma neg_comp (α : Ext X Y n) {m : ℕ} (β : Ext Y Z m) {p : ℕ} (h : n + m = p) : (-α).comp β h = -α.comp β h := by - letI := HasDerivedCategory.standard C; ext; simp [neg_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, neg_hom'] @[simp] lemma comp_neg (α : Ext X Y n) {m : ℕ} (β : Ext Y Z m) {p : ℕ} (h : n + m = p) : α.comp (-β) h = -α.comp β h := by - letI := HasDerivedCategory.standard C; ext; simp [neg_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, neg_hom'] variable (X n) in @[simp] lemma zero_comp {m : ℕ} (β : Ext Y Z m) (p : ℕ) (h : n + m = p) : (0 : Ext X Y n).comp β h = 0 := by - letI := HasDerivedCategory.standard C; ext; simp [zero_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, zero_hom'] @[simp] lemma comp_zero (α : Ext X Y n) (Z : C) (m : ℕ) (p : ℕ) (h : n + m = p) : α.comp (0 : Ext Y Z m) h = 0 := by - letI := HasDerivedCategory.standard C; ext; simp [zero_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, zero_hom'] @[simp] lemma mk₀_id_comp (α : Ext X Y n) : @@ -247,7 +247,7 @@ lemma comp_mk₀_id (α : Ext X Y n) : variable (X Y) in @[simp] lemma mk₀_zero : mk₀ (0 : X ⟶ Y) = 0 := by - letI := HasDerivedCategory.standard C; ext; simp [zero_hom'] + letI := HasDerivedCategory.standard C; ext; simp [this, zero_hom'] section diff --git a/Mathlib/Algebra/Homology/Embedding/Basic.lean b/Mathlib/Algebra/Homology/Embedding/Basic.lean index e36261785b6ea..4de24385f83a8 100644 --- a/Mathlib/Algebra/Homology/Embedding/Basic.lean +++ b/Mathlib/Algebra/Homology/Embedding/Basic.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Joël Riou -/ import Mathlib.Algebra.Homology.ComplexShape -import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Algebra.Ring.Int.Defs +import Mathlib.Algebra.Ring.Nat /-! # Embeddings of complex shapes diff --git a/Mathlib/Algebra/Homology/Embedding/Extend.lean b/Mathlib/Algebra/Homology/Embedding/Extend.lean index 5e2f3e79fe10c..6233b7857282a 100644 --- a/Mathlib/Algebra/Homology/Embedding/Extend.lean +++ b/Mathlib/Algebra/Homology/Embedding/Extend.lean @@ -5,6 +5,7 @@ Authors: Joël Riou -/ import Mathlib.Algebra.Homology.Embedding.Basic import Mathlib.Algebra.Homology.Additive +import Mathlib.Algebra.Homology.Opposite /-! # The extension of a homological complex by an embedding of complex shapes @@ -46,6 +47,12 @@ lemma isZero_X {i : Option ι} (hi : i = none) : subst hi exact Limits.isZero_zero _ +/-- The canonical isomorphism `X K.op i ≅ Opposite.op (X K i)`. -/ +noncomputable def XOpIso (i : Option ι) : X K.op i ≅ Opposite.op (X K i) := + match i with + | some _ => Iso.refl _ + | none => IsZero.iso (isZero_X _ rfl) (isZero_X K rfl).op + /-- Auxiliary definition for the `d` field of `HomologicalComplex.extend`. -/ noncomputable def d : ∀ (i j : Option ι), extend.X K i ⟶ extend.X K j | none, _ => 0 @@ -64,6 +71,21 @@ lemma d_eq {i j : Option ι} {a b : ι} (hi : i = some a) (hj : j = some b) : dsimp [XIso, d] erw [id_comp, comp_id] +@[reassoc] +lemma XOpIso_hom_d_op (i j : Option ι) : + (XOpIso K i).hom ≫ (d K j i).op = + d K.op i j ≫ (XOpIso K j).hom := + match i, j with + | none, _ => by + simp only [d_none_eq_zero, d_none_eq_zero', comp_zero, zero_comp, op_zero] + | some i, some j => by + dsimp [XOpIso] + simp only [d_eq _ rfl rfl, Option.some.injEq, d_eq, op_comp, assoc, + id_comp, comp_id] + rfl + | some _, none => by + simp only [d_none_eq_zero, d_none_eq_zero', comp_zero, zero_comp, op_zero] + variable {K L} /-- Auxiliary definition for `HomologicalComplex.extendMap`. -/ @@ -222,6 +244,20 @@ lemma extendMap_zero : extendMap (0 : K ⟶ L) e = 0 := by simp [extendMap_f _ e hi] · apply (K.isZero_extend_X e i' (fun i hi => hi' ⟨i, hi⟩)).eq_of_src +/-- The canonical isomorphism `K.op.extend e.op ≅ (K.extend e).op`. -/ +noncomputable def extendOpIso : K.op.extend e.op ≅ (K.extend e).op := + Hom.isoOfComponents (fun _ ↦ extend.XOpIso _ _) (fun _ _ _ ↦ + extend.XOpIso_hom_d_op _ _ _) + +@[reassoc] +lemma extend_op_d (i' j' : ι') : + (K.op.extend e.op).d i' j' = + (K.extendOpIso e).hom.f i' ≫ ((K.extend e).d j' i').op ≫ + (K.extendOpIso e).inv.f j' := by + have := (K.extendOpIso e).inv.comm i' j' + dsimp at this + rw [← this, ← comp_f_assoc, Iso.hom_inv_id, id_f, id_comp] + end @[simp] diff --git a/Mathlib/Algebra/Homology/Embedding/ExtendHomology.lean b/Mathlib/Algebra/Homology/Embedding/ExtendHomology.lean new file mode 100644 index 0000000000000..123c91edcc3e7 --- /dev/null +++ b/Mathlib/Algebra/Homology/Embedding/ExtendHomology.lean @@ -0,0 +1,143 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Homology.Embedding.Extend +import Mathlib.Algebra.Homology.ShortComplex.HomologicalComplex + +/-! +# Homology of the extension of an homological complex + +Given an embedding `e : c.Embedding c'` and `K : HomologicalComplex C c`, we shall +compute the homology of `K.extend e`. In degrees that are not in the image of `e.f`, +the homology is obviously zero. When `e.f j = j`, we shall construct an isomorphism +`(K.extend e).homology j' ≅ K.homology j` (TODO). + +-/ + +open CategoryTheory Limits Category + +namespace HomologicalComplex + +variable {ι ι' : Type*} {c : ComplexShape ι} {c' : ComplexShape ι'} + {C : Type*} [Category C] [HasZeroMorphisms C] [HasZeroObject C] + +variable (K L M : HomologicalComplex C c) (φ : K ⟶ L) (φ' : L ⟶ M) (e : c.Embedding c') + +namespace extend + +section HomologyData + +variable {i j k : ι} {i' j' k' : ι'} (hj' : e.f j = j') + (hi : c.prev j = i) (hi' : c'.prev j' = i') (hk : c.next j = k) (hk' : c'.next j' = k') + +include hk hk' in +lemma comp_d_eq_zero_iff ⦃W : C⦄ (φ : W ⟶ K.X j) : + φ ≫ K.d j k = 0 ↔ φ ≫ (K.extendXIso e hj').inv ≫ (K.extend e).d j' k' = 0 := by + by_cases hjk : c.Rel j k + · have hk' : e.f k = k' := by rw [← hk', ← hj', c'.next_eq' (e.rel hjk)] + rw [K.extend_d_eq e hj' hk', Iso.inv_hom_id_assoc, + ← cancel_mono (K.extendXIso e hk').inv, zero_comp, assoc] + · simp only [K.shape _ _ hjk, comp_zero, true_iff] + rw [K.extend_d_from_eq_zero e j' k' j hj', comp_zero, comp_zero] + rw [hk] + exact hjk + +namespace leftHomologyData + +variable (cone : KernelFork (K.d j k)) (hcone : IsLimit cone) + +/-- The kernel fork of `(K.extend e).d j' k'` that is deduced from a kernel +fork of `K.d j k `. -/ +@[simp] +noncomputable def kernelFork : KernelFork ((K.extend e).d j' k') := + KernelFork.ofι (cone.ι ≫ (extendXIso K e hj').inv) + (by rw [assoc, ← comp_d_eq_zero_iff K e hj' hk hk' cone.ι, cone.condition]) + +/-- The limit kernel fork of `(K.extend e).d j' k'` that is deduced from a limit +kernel fork of `K.d j k `. -/ +noncomputable def isLimitKernelFork : IsLimit (kernelFork K e hj' hk hk' cone) := + KernelFork.isLimitOfIsLimitOfIff hcone ((K.extend e).d j' k') + (extendXIso K e hj').symm (comp_d_eq_zero_iff K e hj' hk hk') + +variable (cocone : CokernelCofork (hcone.lift (KernelFork.ofι (K.d i j) (K.d_comp_d i j k)))) + (hcocone : IsColimit cocone) + +include hi hi' hcone in +/-- Auxiliary lemma for `lift_d_comp_eq_zero_iff`. -/ +lemma lift_d_comp_eq_zero_iff' ⦃W : C⦄ (f' : K.X i ⟶ cone.pt) + (hf' : f' ≫ cone.ι = K.d i j) + (f'' : (K.extend e).X i' ⟶ cone.pt) + (hf'' : f'' ≫ cone.ι ≫ (extendXIso K e hj').inv = (K.extend e).d i' j') + (φ : cone.pt ⟶ W) : + f' ≫ φ = 0 ↔ f'' ≫ φ = 0 := by + by_cases hij : c.Rel i j + · have hi'' : e.f i = i' := by rw [← hi', ← hj', c'.prev_eq' (e.rel hij)] + have : (K.extendXIso e hi'').hom ≫ f' = f'' := by + apply Fork.IsLimit.hom_ext hcone + rw [assoc, hf', ← cancel_mono (extendXIso K e hj').inv, assoc, assoc, hf'', + K.extend_d_eq e hi'' hj'] + rw [← cancel_epi (K.extendXIso e hi'').hom, comp_zero, ← this, assoc] + · have h₁ : f' = 0 := by + apply Fork.IsLimit.hom_ext hcone + simp only [zero_comp, hf', K.shape _ _ hij] + have h₂ : f'' = 0 := by + apply Fork.IsLimit.hom_ext hcone + dsimp + rw [← cancel_mono (extendXIso K e hj').inv, assoc, hf'', zero_comp, zero_comp, + K.extend_d_to_eq_zero e i' j' j hj'] + rw [hi] + exact hij + simp [h₁, h₂] + +include hi hi' in +lemma lift_d_comp_eq_zero_iff ⦃W : C⦄ (φ : cone.pt ⟶ W) : + hcone.lift (KernelFork.ofι (K.d i j) (K.d_comp_d i j k)) ≫ φ = 0 ↔ + ((isLimitKernelFork K e hj' hk hk' cone hcone).lift + (KernelFork.ofι ((K.extend e).d i' j') (d_comp_d _ _ _ _))) ≫ φ = 0 := + lift_d_comp_eq_zero_iff' K e hj' hi hi' cone hcone _ (hcone.fac _ _) _ + (IsLimit.fac _ _ WalkingParallelPair.zero) _ + +/-- Auxiliary definition for `extend.leftHomologyData`. -/ +noncomputable def cokernelCofork : + CokernelCofork ((isLimitKernelFork K e hj' hk hk' cone hcone).lift + (KernelFork.ofι ((K.extend e).d i' j') (d_comp_d _ _ _ _))) := + CokernelCofork.ofπ cocone.π (by + rw [← lift_d_comp_eq_zero_iff K e hj' hi hi' hk hk' cone hcone] + exact cocone.condition) + +/-- Auxiliary definition for `extend.leftHomologyData`. -/ +noncomputable def isColimitCokernelCofork : + IsColimit (cokernelCofork K e hj' hi hi' hk hk' cone hcone cocone) := + CokernelCofork.isColimitOfIsColimitOfIff' hcocone _ + (lift_d_comp_eq_zero_iff K e hj' hi hi' hk hk' cone hcone) + +end leftHomologyData + +open leftHomologyData in +/-- The left homology data of `(K.extend e).sc' i' j' k'` that is deduced +from a left homology data of `K.sc' i j k`. -/ +@[simps] +noncomputable def leftHomologyData (h : (K.sc' i j k).LeftHomologyData) : + ((K.extend e).sc' i' j' k').LeftHomologyData where + K := h.K + H := h.H + i := h.i ≫ (extendXIso K e hj').inv + π := h.π + wi := by + dsimp + rw [assoc, ← comp_d_eq_zero_iff K e hj' hk hk'] + exact h.wi + hi := isLimitKernelFork K e hj' hk hk' _ h.hi + wπ := by + dsimp + rw [← lift_d_comp_eq_zero_iff K e hj' hi hi' hk hk' _ h.hi] + exact h.wπ + hπ := isColimitCokernelCofork K e hj' hi hi' hk hk' _ h.hi _ h.hπ + +end HomologyData + +end extend + +end HomologicalComplex diff --git a/Mathlib/Algebra/Homology/Embedding/TruncGE.lean b/Mathlib/Algebra/Homology/Embedding/TruncGE.lean index c0c9a8b3cbd18..8bac0da93a294 100644 --- a/Mathlib/Algebra/Homology/Embedding/TruncGE.lean +++ b/Mathlib/Algebra/Homology/Embedding/TruncGE.lean @@ -128,6 +128,8 @@ lemma truncGE'_d_eq_fromOpcycles {i j : ι} (hij : c.Rel i j) {i' j' : ι'} subst hi' hj' simp [truncGE'XIso, truncGE'XIsoOpcycles] +section + variable [HasZeroObject C] /-- The canonical truncation of a homological complex relative to an embedding @@ -146,4 +148,100 @@ noncomputable def truncGEXIsoOpcycles {i : ι} {i' : ι'} (hi' : e.f i = i') (hi (K.truncGE e).X i' ≅ K.opcycles i' := (K.truncGE' e).extendXIso e hi' ≪≫ K.truncGE'XIsoOpcycles e hi' hi +end + +section + +variable {K L M} + +open Classical in +/-- The morphism `K.truncGE' e ⟶ L.truncGE' e` induced by a morphism `K ⟶ L`. -/ +noncomputable def truncGE'Map : K.truncGE' e ⟶ L.truncGE' e where + f i := + if hi : e.BoundaryGE i + then + (K.truncGE'XIsoOpcycles e rfl hi).hom ≫ opcyclesMap φ (e.f i) ≫ + (L.truncGE'XIsoOpcycles e rfl hi).inv + else + (K.truncGE'XIso e rfl hi).hom ≫ φ.f (e.f i) ≫ (L.truncGE'XIso e rfl hi).inv + comm' i j hij := by + dsimp + rw [dif_neg (e.not_boundaryGE_next hij)] + by_cases hi : e.BoundaryGE i + · rw [dif_pos hi] + simp [truncGE'_d_eq_fromOpcycles _ e hij rfl rfl hi, + ← cancel_epi (K.pOpcycles (e.f i))] + · rw [dif_neg hi] + simp [truncGE'_d_eq _ e hij rfl rfl hi] + +lemma truncGE'Map_f_eq_opcyclesMap {i : ι} (hi : e.BoundaryGE i) {i' : ι'} (h : e.f i = i') : + (truncGE'Map φ e).f i = + (K.truncGE'XIsoOpcycles e h hi).hom ≫ opcyclesMap φ i' ≫ + (L.truncGE'XIsoOpcycles e h hi).inv := by + subst h + exact dif_pos hi + +lemma truncGE'Map_f_eq {i : ι} (hi : ¬ e.BoundaryGE i) {i' : ι'} (h : e.f i = i') : + (truncGE'Map φ e).f i = + (K.truncGE'XIso e h hi).hom ≫ φ.f i' ≫ (L.truncGE'XIso e h hi).inv := by + subst h + exact dif_neg hi + +variable (K) in +@[simp] +lemma truncGE'Map_id : truncGE'Map (𝟙 K) e = 𝟙 _ := by + ext i + by_cases hi : e.BoundaryGE i + · simp [truncGE'Map_f_eq_opcyclesMap _ _ hi rfl] + · simp [truncGE'Map_f_eq _ _ hi rfl] + +@[reassoc, simp] +lemma truncGE'Map_comp : truncGE'Map (φ ≫ φ') e = truncGE'Map φ e ≫ truncGE'Map φ' e := by + ext i + by_cases hi : e.BoundaryGE i + · simp [truncGE'Map_f_eq_opcyclesMap _ _ hi rfl, opcyclesMap_comp] + · simp [truncGE'Map_f_eq _ _ hi rfl] + +variable [HasZeroObject C] + +/-- The morphism `K.truncGE e ⟶ L.truncGE e` induced by a morphism `K ⟶ L`. -/ +noncomputable def truncGEMap : K.truncGE e ⟶ L.truncGE e := + (e.extendFunctor C).map (truncGE'Map φ e) + +variable (K) in +@[simp] +lemma truncGEMap_id : truncGEMap (𝟙 K) e = 𝟙 _ := by + simp [truncGEMap, truncGE] + +@[reassoc, simp] +lemma truncGEMap_comp : truncGEMap (φ ≫ φ') e = truncGEMap φ e ≫ truncGEMap φ' e := by + simp [truncGEMap, truncGE] + +end + end HomologicalComplex + +namespace ComplexShape.Embedding + +variable (e : Embedding c c') [e.IsTruncGE] + (C : Type*) [Category C] [HasZeroMorphisms C] [HasZeroObject C] [CategoryWithHomology C] + +/-- Given an embedding `e : Embedding c c'` of complex shapes which satisfy `e.IsTruncGE`, +this is the (canonical) truncation functor +`HomologicalComplex C c' ⥤ HomologicalComplex C c`. -/ +@[simps] +noncomputable def truncGE'Functor : + HomologicalComplex C c' ⥤ HomologicalComplex C c where + obj K := K.truncGE' e + map φ := HomologicalComplex.truncGE'Map φ e + +/-- Given an embedding `e : Embedding c c'` of complex shapes which satisfy `e.IsTruncGE`, +this is the (canonical) truncation functor +`HomologicalComplex C c' ⥤ HomologicalComplex C c'`. -/ +@[simps] +noncomputable def truncGEFunctor : + HomologicalComplex C c' ⥤ HomologicalComplex C c' where + obj K := K.truncGE e + map φ := HomologicalComplex.truncGEMap φ e + +end ComplexShape.Embedding diff --git a/Mathlib/Algebra/Homology/LocalCohomology.lean b/Mathlib/Algebra/Homology/LocalCohomology.lean index a66ee204117c8..c98cac0916bc0 100644 --- a/Mathlib/Algebra/Homology/LocalCohomology.lean +++ b/Mathlib/Algebra/Homology/LocalCohomology.lean @@ -66,9 +66,7 @@ variable {R : Type u} [CommRing R] {D : Type v} [SmallCategory D] determined by the functor `I` -/ def ringModIdeals (I : D ⥤ Ideal R) : D ⥤ ModuleCat.{u} R where obj t := ModuleCat.of R <| R ⧸ I.obj t - map w := Submodule.mapQ _ _ LinearMap.id (I.map w).down.down - -- Porting note: was 'obviously' - map_comp f g := by apply Submodule.linearMap_qext; rfl + map w := ModuleCat.ofHom <| Submodule.mapQ _ _ LinearMap.id (I.map w).down.down -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11215): TODO: Once this file is ported, move this instance to the right location. instance moduleCat_enoughProjectives' : EnoughProjectives (ModuleCat.{u} R) := diff --git a/Mathlib/Algebra/Homology/Opposite.lean b/Mathlib/Algebra/Homology/Opposite.lean index ba39dfe50ab4e..e234cce59912e 100644 --- a/Mathlib/Algebra/Homology/Opposite.lean +++ b/Mathlib/Algebra/Homology/Opposite.lean @@ -213,6 +213,16 @@ instance (K : HomologicalComplex Vᵒᵖ c) (i : ι) [K.HasHomology i] : K.unop.HasHomology i := (inferInstance : (K.sc i).unop.HasHomology) +instance (K : HomologicalComplex V c) (i : ι) [K.HasHomology i] : + ((opFunctor _ _).obj (op K)).HasHomology i := by + dsimp + infer_instance + +instance (K : HomologicalComplex Vᵒᵖ c) (i : ι) [K.HasHomology i] : + ((unopFunctor _ _).obj (op K)).HasHomology i := by + dsimp + infer_instance + variable {V c} /-- If `K` is a homological complex, then the homology of `K.op` identifies to @@ -227,6 +237,100 @@ def homologyUnop (K : HomologicalComplex Vᵒᵖ c) (i : ι) [K.HasHomology i] : K.unop.homology i ≅ unop (K.homology i) := (K.unop.homologyOp i).unop +section + +variable (K : HomologicalComplex V c) (i : ι) [K.HasHomology i] + +/-- The canonical isomorphism `K.op.cycles i ≅ op (K.opcycles i)`. -/ +def cyclesOpIso : K.op.cycles i ≅ op (K.opcycles i) := + (K.sc i).cyclesOpIso + +/-- The canonical isomorphism `K.op.opcycles i ≅ op (K.cycles i)`. -/ +def opcyclesOpIso : K.op.opcycles i ≅ op (K.cycles i) := + (K.sc i).opcyclesOpIso + +variable (j : ι) + +@[reassoc (attr := simp)] +lemma opcyclesOpIso_hom_toCycles_op : + (K.opcyclesOpIso i).hom ≫ (K.toCycles j i).op = K.op.fromOpcycles i j := by + by_cases hij : c.Rel j i + · obtain rfl := c.prev_eq' hij + exact (K.sc i).opcyclesOpIso_hom_toCycles_op + · rw [K.toCycles_eq_zero hij, K.op.fromOpcycles_eq_zero hij, op_zero, comp_zero] + +@[reassoc (attr := simp)] +lemma fromOpcycles_op_cyclesOpIso_inv : + (K.fromOpcycles i j).op ≫ (K.cyclesOpIso i).inv = K.op.toCycles j i := by + by_cases hij : c.Rel i j + · obtain rfl := c.next_eq' hij + exact (K.sc i).fromOpcycles_op_cyclesOpIso_inv + · rw [K.op.toCycles_eq_zero hij, K.fromOpcycles_eq_zero hij, op_zero, zero_comp] + +end + +section + +variable {K L : HomologicalComplex V c} (φ : K ⟶ L) (i : ι) + [K.HasHomology i] [L.HasHomology i] + +@[reassoc] +lemma homologyOp_hom_naturality : + homologyMap ((opFunctor _ _).map φ.op) _ ≫ (K.homologyOp i).hom = + (L.homologyOp i).hom ≫ (homologyMap φ i).op := + ShortComplex.homologyOpIso_hom_naturality ((shortComplexFunctor V c i).map φ) + +@[reassoc] +lemma opcyclesOpIso_hom_naturality : + opcyclesMap ((opFunctor _ _).map φ.op) _ ≫ (K.opcyclesOpIso i).hom = + (L.opcyclesOpIso i).hom ≫ (cyclesMap φ i).op := + ShortComplex.opcyclesOpIso_hom_naturality ((shortComplexFunctor V c i).map φ) + +@[reassoc] +lemma opcyclesOpIso_inv_naturality : + (cyclesMap φ i).op ≫ (K.opcyclesOpIso i).inv = + (L.opcyclesOpIso i).inv ≫ opcyclesMap ((opFunctor _ _).map φ.op) _ := + ShortComplex.opcyclesOpIso_inv_naturality ((shortComplexFunctor V c i).map φ) + +@[reassoc] +lemma cyclesOpIso_hom_naturality : + cyclesMap ((opFunctor _ _).map φ.op) _ ≫ (K.cyclesOpIso i).hom = + (L.cyclesOpIso i).hom ≫ (opcyclesMap φ i).op := + ShortComplex.cyclesOpIso_hom_naturality ((shortComplexFunctor V c i).map φ) + +@[reassoc] +lemma cyclesOpIso_inv_naturality : + (opcyclesMap φ i).op ≫ (K.cyclesOpIso i).inv = + (L.cyclesOpIso i).inv ≫ cyclesMap ((opFunctor _ _).map φ.op) _ := + ShortComplex.cyclesOpIso_inv_naturality ((shortComplexFunctor V c i).map φ) + +end + +section + +variable (V c) [CategoryWithHomology V] (i : ι) + +/-- The natural isomorphism `K.op.cycles i ≅ op (K.opcycles i)`. -/ +@[simps!] +def cyclesOpNatIso : + opFunctor V c ⋙ cyclesFunctor Vᵒᵖ c.symm i ≅ (opcyclesFunctor V c i).op := + NatIso.ofComponents (fun K ↦ (unop K).cyclesOpIso i) + (fun _ ↦ cyclesOpIso_hom_naturality _ _) + +/-- The natural isomorphism `K.op.opcycles i ≅ op (K.cycles i)`. -/ +def opcyclesOpNatIso : + opFunctor V c ⋙ opcyclesFunctor Vᵒᵖ c.symm i ≅ (cyclesFunctor V c i).op := + NatIso.ofComponents (fun K ↦ (unop K).opcyclesOpIso i) + (fun _ ↦ opcyclesOpIso_hom_naturality _ _) + +/-- The natural isomorphism `K.op.homology i ≅ op (K.homology i)`. -/ +def homologyOpNatIso : + opFunctor V c ⋙ homologyFunctor Vᵒᵖ c.symm i ≅ (homologyFunctor V c i).op := + NatIso.ofComponents (fun K ↦ (unop K).homologyOp i) + (fun _ ↦ homologyOp_hom_naturality _ _) + +end + end section diff --git a/Mathlib/Algebra/Homology/ShortComplex/Abelian.lean b/Mathlib/Algebra/Homology/ShortComplex/Abelian.lean index 7bc3d040b42d2..ad19544a15033 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Abelian.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Abelian.lean @@ -84,7 +84,8 @@ noncomputable def ofAbelian : S.LeftHomologyData := by IsLimit.conePointUniqueUpToIso_hom_comp _ _ WalkingParallelPair.zero have fac : f' = Abelian.factorThruImage S.f ≫ e.hom ≫ kernel.ι γ := by rw [hf', he] - simp only [f', kernel.lift_ι, abelianImageToKernel, ← cancel_mono (kernel.ι S.g), assoc] + simp only [γ, f', kernel.lift_ι, abelianImageToKernel, ← cancel_mono (kernel.ι S.g), + assoc] have hπ : IsColimit (CokernelCofork.ofπ _ wπ) := CokernelCofork.IsColimit.ofπ _ _ (fun x hx => cokernel.desc _ x (by @@ -150,7 +151,7 @@ noncomputable def ofAbelian : S.RightHomologyData := by IsColimit.comp_coconePointUniqueUpToIso_hom _ _ WalkingParallelPair.one have fac : g' = cokernel.π γ ≫ e.hom ≫ Abelian.factorThruCoimage S.g := by rw [hg', reassoc_of% he] - simp only [g', cokernel.π_desc, ← cancel_epi (cokernel.π S.f), + simp only [γ, g', cokernel.π_desc, ← cancel_epi (cokernel.π S.f), cokernel_π_comp_cokernelToAbelianCoimage_assoc] have hι : IsLimit (KernelFork.ofι _ wι) := KernelFork.IsLimit.ofι _ _ diff --git a/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean index fb3e8617e352d..415cac78ef15f 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/HomologicalComplex.lean @@ -149,6 +149,11 @@ lemma d_toCycles [K.HasHomology k] : K.d i j ≫ K.toCycles j k = 0 := by simp only [← cancel_mono (K.iCycles k), assoc, toCycles_i, d_comp_d, zero_comp] +variable {i j} in +lemma toCycles_eq_zero [K.HasHomology j] (hij : ¬ c.Rel i j) : + K.toCycles i j = 0 := by + rw [← cancel_mono (K.iCycles j), toCycles_i, zero_comp, K.shape _ _ hij] + variable {i} section @@ -258,6 +263,11 @@ lemma fromOpcycles_d : K.fromOpcycles i j ≫ K.d j k = 0 := by simp only [← cancel_epi (K.pOpcycles i), p_fromOpcycles_assoc, d_comp_d, comp_zero] +variable {i j} in +lemma fromOpcycles_eq_zero (hij : ¬ c.Rel i j) : + K.fromOpcycles i j = 0 := by + rw [← cancel_epi (K.pOpcycles i), p_fromOpcycles, comp_zero, K.shape _ _ hij] + variable {i} @[reassoc] diff --git a/Mathlib/Algebra/Homology/ShortComplex/Homology.lean b/Mathlib/Algebra/Homology/ShortComplex/Homology.lean index 0c416a49f4df5..9f3d4faff0bed 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/Homology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/Homology.lean @@ -1036,6 +1036,18 @@ lemma homologyMap_op [HasHomology S₁] [HasHomology S₂] : simp only [assoc, rightHomologyMap'_op, op_comp, ← leftHomologyMap'_comp_assoc, id_comp, opMap_id, comp_id, HomologyData.op_left] +@[reassoc] +lemma homologyOpIso_hom_naturality [S₁.HasHomology] [S₂.HasHomology] : + homologyMap (opMap φ) ≫ (S₁.homologyOpIso).hom = + S₂.homologyOpIso.hom ≫ (homologyMap φ).op := by + simp [homologyMap_op] + +@[reassoc] +lemma homologyOpIso_inv_naturality [S₁.HasHomology] [S₂.HasHomology] : + (homologyMap φ).op ≫ (S₁.homologyOpIso).inv = + S₂.homologyOpIso.inv ≫ homologyMap (opMap φ) := by + simp [homologyMap_op] + variable (C) /-- The natural isomorphism `(homologyFunctor C).op ≅ opFunctor C ⋙ homologyFunctor Cᵒᵖ` @@ -1043,7 +1055,7 @@ which relates the homology in `C` and in `Cᵒᵖ`. -/ noncomputable def homologyFunctorOpNatIso [CategoryWithHomology C] : (homologyFunctor C).op ≅ opFunctor C ⋙ homologyFunctor Cᵒᵖ := NatIso.ofComponents (fun S => S.unop.homologyOpIso.symm) - (by simp [homologyMap_op]) + (fun _ ↦ homologyOpIso_inv_naturality _) variable {C} {A : C} diff --git a/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean b/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean index 59034f288455b..87236bc52bb4d 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/ModuleCat.lean @@ -33,7 +33,7 @@ linear maps `f` and `g` and the vanishing of their composition. -/ def moduleCatMk {X₁ X₂ X₃ : Type v} [AddCommGroup X₁] [AddCommGroup X₂] [AddCommGroup X₃] [Module R X₁] [Module R X₂] [Module R X₃] (f : X₁ →ₗ[R] X₂) (g : X₂ →ₗ[R] X₃) (hfg : g.comp f = 0) : ShortComplex (ModuleCat.{v} R) := - ShortComplex.mk (ModuleCat.asHom f) (ModuleCat.asHom g) hfg + ShortComplex.mk (ModuleCat.ofHom f) (ModuleCat.ofHom g) (ModuleCat.hom_ext hfg) variable (S : ShortComplex (ModuleCat.{v} R)) @@ -46,33 +46,19 @@ lemma moduleCat_exact_iff : S.exact_iff_of_concreteCategory lemma moduleCat_exact_iff_ker_sub_range : - S.Exact ↔ LinearMap.ker S.g ≤ LinearMap.range S.f := by + S.Exact ↔ LinearMap.ker S.g.hom ≤ LinearMap.range S.f.hom := by rw [moduleCat_exact_iff] - constructor - · intro h x₂ hx₂ - exact h x₂ hx₂ - · intro h x₂ hx₂ - exact h hx₂ + aesop lemma moduleCat_exact_iff_range_eq_ker : - S.Exact ↔ LinearMap.range S.f = LinearMap.ker S.g := by + S.Exact ↔ LinearMap.range S.f.hom = LinearMap.ker S.g.hom := by rw [moduleCat_exact_iff_ker_sub_range] - constructor - · intro h - ext x - constructor - · rintro ⟨y, hy⟩ - rw [← hy] - simp only [LinearMap.mem_ker, moduleCat_zero_apply] - · intro hx - exact h hx - · intro h - rw [h] + aesop variable {S} lemma Exact.moduleCat_range_eq_ker (hS : S.Exact) : - LinearMap.range S.f = LinearMap.ker S.g := by + LinearMap.range S.f.hom = LinearMap.ker S.g.hom := by simpa only [moduleCat_exact_iff_range_eq_ker] using hS lemma ShortExact.moduleCat_injective_f (hS : S.ShortExact) : @@ -94,19 +80,17 @@ lemma ShortExact.moduleCat_exact_iff_function_exact : morphisms `f` and `g` and the assumption `LinearMap.range f ≤ LinearMap.ker g`. -/ @[simps] def moduleCatMkOfKerLERange {X₁ X₂ X₃ : ModuleCat.{v} R} (f : X₁ ⟶ X₂) (g : X₂ ⟶ X₃) - (hfg : LinearMap.range f ≤ LinearMap.ker g) : ShortComplex (ModuleCat.{v} R) := - ShortComplex.mk f g (by - ext - exact hfg ⟨_, rfl⟩) + (hfg : LinearMap.range f.hom ≤ LinearMap.ker g.hom) : ShortComplex (ModuleCat.{v} R) := + ShortComplex.mk f g (by aesop) lemma Exact.moduleCat_of_range_eq_ker {X₁ X₂ X₃ : ModuleCat.{v} R} - (f : X₁ ⟶ X₂) (g : X₂ ⟶ X₃) (hfg : LinearMap.range f = LinearMap.ker g) : + (f : X₁ ⟶ X₂) (g : X₂ ⟶ X₃) (hfg : LinearMap.range f.hom = LinearMap.ker g.hom) : (moduleCatMkOfKerLERange f g (by rw [hfg])).Exact := by simpa only [moduleCat_exact_iff_range_eq_ker] using hfg /-- The canonical linear map `S.X₁ →ₗ[R] LinearMap.ker S.g` induced by `S.f`. -/ @[simps] -def moduleCatToCycles : S.X₁ →ₗ[R] LinearMap.ker S.g where +def moduleCatToCycles : S.X₁ →ₗ[R] LinearMap.ker S.g.hom where toFun x := ⟨S.f x, S.moduleCat_zero_apply x⟩ map_add' x y := by aesop map_smul' a x := by aesop @@ -114,35 +98,28 @@ def moduleCatToCycles : S.X₁ →ₗ[R] LinearMap.ker S.g where /-- 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) + ModuleCat.of R (LinearMap.ker S.g.hom ⧸ 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 +abbrev moduleCatHomologyπ : ModuleCat.of R (LinearMap.ker S.g.hom) ⟶ S.moduleCatHomology := + ModuleCat.ofHom (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] +@[simps K H i π] def moduleCatLeftHomologyData : S.LeftHomologyData where - K := ModuleCat.of R (LinearMap.ker S.g) + K := ModuleCat.of R (LinearMap.ker S.g.hom) H := S.moduleCatHomology - i := (LinearMap.ker S.g).subtype + i := ModuleCat.ofHom (LinearMap.ker S.g.hom).subtype π := S.moduleCatHomologyπ - wi := by - ext ⟨_, hx⟩ - exact hx + wi := by aesop hi := ModuleCat.kernelIsLimit _ - wπ := by - ext (x : S.X₁) - dsimp - erw [Submodule.Quotient.mk_eq_zero] - rw [LinearMap.mem_range] - apply exists_apply_eq_apply - hπ := ModuleCat.cokernelIsColimit (ModuleCat.asHom S.moduleCatToCycles) + wπ := by aesop + hπ := ModuleCat.cokernelIsColimit (ModuleCat.ofHom S.moduleCatToCycles) @[simp] lemma moduleCatLeftHomologyData_f' : - S.moduleCatLeftHomologyData.f' = S.moduleCatToCycles := rfl + S.moduleCatLeftHomologyData.f' = ModuleCat.ofHom S.moduleCatToCycles := rfl instance : Epi S.moduleCatHomologyπ := (inferInstance : Epi S.moduleCatLeftHomologyData.π) @@ -150,22 +127,22 @@ instance : Epi S.moduleCatHomologyπ := /-- 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) := +noncomputable def moduleCatCyclesIso : S.cycles ≅ ModuleCat.of R (LinearMap.ker S.g.hom) := S.moduleCatLeftHomologyData.cyclesIso @[reassoc (attr := simp, elementwise)] lemma moduleCatCyclesIso_hom_subtype : - S.moduleCatCyclesIso.hom ≫ (LinearMap.ker S.g).subtype = S.iCycles := + S.moduleCatCyclesIso.hom ≫ ModuleCat.ofHom (LinearMap.ker S.g.hom).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.moduleCatCyclesIso.inv ≫ S.iCycles = ModuleCat.ofHom (LinearMap.ker S.g.hom).subtype := S.moduleCatLeftHomologyData.cyclesIso_inv_comp_iCycles @[reassoc (attr := simp, elementwise)] lemma toCycles_moduleCatCyclesIso_hom : - S.toCycles ≫ S.moduleCatCyclesIso.hom = S.moduleCatToCycles := by + S.toCycles ≫ S.moduleCatCyclesIso.hom = ModuleCat.ofHom S.moduleCatToCycles := by rw [← cancel_mono S.moduleCatLeftHomologyData.i, moduleCatLeftHomologyData_i, Category.assoc, S.moduleCatCyclesIso_hom_subtype, toCycles_i] rfl diff --git a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean index 3592289533893..9832970621a74 100644 --- a/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean +++ b/Mathlib/Algebra/Homology/ShortComplex/RightHomology.lean @@ -964,6 +964,70 @@ noncomputable def cyclesOpIso [S.HasRightHomology] : S.op.cycles ≅ Opposite.op S.opcycles := S.rightHomologyData.op.cyclesIso +@[reassoc (attr := simp)] +lemma opcyclesOpIso_hom_toCycles_op [S.HasLeftHomology] : + S.opcyclesOpIso.hom ≫ S.toCycles.op = S.op.fromOpcycles := by + dsimp [opcyclesOpIso, toCycles] + rw [← cancel_epi S.op.pOpcycles, p_fromOpcycles, + RightHomologyData.pOpcycles_comp_opcyclesIso_hom_assoc, + LeftHomologyData.op_p, ← op_comp, LeftHomologyData.f'_i, op_g] + +@[reassoc (attr := simp)] +lemma fromOpcycles_op_cyclesOpIso_inv [S.HasRightHomology]: + S.fromOpcycles.op ≫ S.cyclesOpIso.inv = S.op.toCycles := by + dsimp [cyclesOpIso, fromOpcycles] + rw [← cancel_mono S.op.iCycles, assoc, toCycles_i, + LeftHomologyData.cyclesIso_inv_comp_iCycles, RightHomologyData.op_i, + ← op_comp, RightHomologyData.p_g', op_f] + +@[reassoc (attr := simp)] +lemma op_pOpcycles_opcyclesOpIso_hom [S.HasLeftHomology] : + S.op.pOpcycles ≫ S.opcyclesOpIso.hom = S.iCycles.op := by + dsimp [opcyclesOpIso] + rw [← S.leftHomologyData.op.p_comp_opcyclesIso_inv, assoc, + Iso.inv_hom_id, comp_id] + rfl + +@[reassoc (attr := simp)] +lemma cyclesOpIso_inv_op_iCycles [S.HasRightHomology] : + S.cyclesOpIso.inv ≫ S.op.iCycles = S.pOpcycles.op := by + dsimp [cyclesOpIso] + rw [← S.rightHomologyData.op.cyclesIso_hom_comp_i, Iso.inv_hom_id_assoc] + rfl + +@[reassoc] +lemma opcyclesOpIso_hom_naturality (φ : S₁ ⟶ S₂) + [S₁.HasLeftHomology] [S₂.HasLeftHomology] : + opcyclesMap (opMap φ) ≫ (S₁.opcyclesOpIso).hom = + S₂.opcyclesOpIso.hom ≫ (cyclesMap φ).op := by + rw [← cancel_epi S₂.op.pOpcycles, p_opcyclesMap_assoc, opMap_τ₂, + op_pOpcycles_opcyclesOpIso_hom, op_pOpcycles_opcyclesOpIso_hom_assoc, ← op_comp, + ← op_comp, cyclesMap_i] + +@[reassoc] +lemma opcyclesOpIso_inv_naturality (φ : S₁ ⟶ S₂) + [S₁.HasLeftHomology] [S₂.HasLeftHomology] : + (cyclesMap φ).op ≫ (S₁.opcyclesOpIso).inv = + S₂.opcyclesOpIso.inv ≫ opcyclesMap (opMap φ) := by + rw [← cancel_epi (S₂.opcyclesOpIso.hom), Iso.hom_inv_id_assoc, + ← opcyclesOpIso_hom_naturality_assoc, Iso.hom_inv_id, comp_id] + +@[reassoc] +lemma cyclesOpIso_inv_naturality (φ : S₁ ⟶ S₂) + [S₁.HasRightHomology] [S₂.HasRightHomology] : + (opcyclesMap φ).op ≫ (S₁.cyclesOpIso).inv = + S₂.cyclesOpIso.inv ≫ cyclesMap (opMap φ) := by + rw [← cancel_mono S₁.op.iCycles, assoc, assoc, cyclesOpIso_inv_op_iCycles, cyclesMap_i, + cyclesOpIso_inv_op_iCycles_assoc, ← op_comp, p_opcyclesMap, op_comp, opMap_τ₂] + +@[reassoc] +lemma cyclesOpIso_hom_naturality (φ : S₁ ⟶ S₂) + [S₁.HasRightHomology] [S₂.HasRightHomology] : + cyclesMap (opMap φ) ≫ (S₁.cyclesOpIso).hom = + S₂.cyclesOpIso.hom ≫ (opcyclesMap φ).op := by + rw [← cancel_mono (S₁.cyclesOpIso).inv, assoc, assoc, Iso.hom_inv_id, comp_id, + cyclesOpIso_inv_naturality, Iso.hom_inv_id_assoc] + @[simp] lemma leftHomologyMap'_op (φ : S₁ ⟶ S₂) (h₁ : S₁.LeftHomologyData) (h₂ : S₂.LeftHomologyData) : diff --git a/Mathlib/Algebra/IsPrimePow.lean b/Mathlib/Algebra/IsPrimePow.lean index c21cf0363fe86..d9de71addc9b7 100644 --- a/Mathlib/Algebra/IsPrimePow.lean +++ b/Mathlib/Algebra/IsPrimePow.lean @@ -71,7 +71,7 @@ theorem isPrimePow_nat_iff_bounded (n : ℕ) : rw [isPrimePow_nat_iff] refine Iff.symm ⟨fun ⟨p, _, k, _, hp, hk, hn⟩ => ⟨p, k, hp, hk, hn⟩, ?_⟩ rintro ⟨p, k, hp, hk, rfl⟩ - refine ⟨p, ?_, k, (Nat.lt_pow_self hp.one_lt _).le, 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_pow_right hp.one_lt.le hk diff --git a/Mathlib/Algebra/Lie/CartanExists.lean b/Mathlib/Algebra/Lie/CartanExists.lean index 5ee149734e3b5..cca8926c878a6 100644 --- a/Mathlib/Algebra/Lie/CartanExists.lean +++ b/Mathlib/Algebra/Lie/CartanExists.lean @@ -320,7 +320,7 @@ lemma engel_isBot_of_isMin (hLK : finrank K L ≤ #K) (U : LieSubalgebra K L) rw [← hn] clear hn induction n with - | zero => simp only [pow_zero, LinearMap.one_apply] + | zero => simp only [z', pow_zero, LinearMap.one_apply] | succ n ih => rw [pow_succ', pow_succ', LinearMap.mul_apply, ih]; rfl classical -- Now let `n` be the smallest power such that `⁅v, _⁆ ^ n` kills `z'`. diff --git a/Mathlib/Algebra/Lie/Quotient.lean b/Mathlib/Algebra/Lie/Quotient.lean index e6ae53a34c3e9..367d16adeac24 100644 --- a/Mathlib/Algebra/Lie/Quotient.lean +++ b/Mathlib/Algebra/Lie/Quotient.lean @@ -43,7 +43,7 @@ instance : HasQuotient M (LieSubmodule R L M) := namespace Quotient -variable {N I} +variable {N} instance addCommGroup : AddCommGroup (M ⧸ N) := Submodule.Quotient.addCommGroup _ diff --git a/Mathlib/Algebra/Lie/Semisimple/Basic.lean b/Mathlib/Algebra/Lie/Semisimple/Basic.lean index 50b8820a1addc..791f324394561 100644 --- a/Mathlib/Algebra/Lie/Semisimple/Basic.lean +++ b/Mathlib/Algebra/Lie/Semisimple/Basic.lean @@ -212,7 +212,11 @@ lemma finitelyAtomistic : ∀ s : Finset (LieIdeal R L), ↑s ⊆ {I : LieIdeal set K := s'.sup id suffices I ≤ K by obtain ⟨t, hts', htI⟩ := finitelyAtomistic s' hs'S I this - exact ⟨t, hts'.trans hs'.subset, htI⟩ + #adaptation_note + /-- Prior to https://github.com/leanprover/lean4/pull/6024 + we could write `hts'.trans hs'.subset` instead of + `Finset.Subset.trans hts' hs'.subset` in the next line. -/ + exact ⟨t, Finset.Subset.trans hts' hs'.subset, htI⟩ -- Since `I` is contained in the supremum of `J` with the supremum of `s'`, -- any element `x` of `I` can be written as `y + z` for some `y ∈ J` and `z ∈ K`. intro x hx diff --git a/Mathlib/Algebra/Lie/Solvable.lean b/Mathlib/Algebra/Lie/Solvable.lean index 1ce5fd8fdcf58..4a9632102afc4 100644 --- a/Mathlib/Algebra/Lie/Solvable.lean +++ b/Mathlib/Algebra/Lie/Solvable.lean @@ -77,7 +77,7 @@ theorem derivedSeriesOfIdeal_add (k l : ℕ) : D (k + l) I = D k (D l I) := by | zero => rw [Nat.zero_add, derivedSeriesOfIdeal_zero] | succ k ih => rw [Nat.succ_add k l, derivedSeriesOfIdeal_succ, derivedSeriesOfIdeal_succ, ih] -@[mono] +@[gcongr, mono] theorem derivedSeriesOfIdeal_le {I J : LieIdeal R L} {k l : ℕ} (h₁ : I ≤ J) (h₂ : l ≤ k) : D k I ≤ D l J := by revert l; induction' k with k ih <;> intro l h₂ diff --git a/Mathlib/Algebra/Lie/Submodule.lean b/Mathlib/Algebra/Lie/Submodule.lean index 1201232787862..3408e81f11011 100644 --- a/Mathlib/Algebra/Lie/Submodule.lean +++ b/Mathlib/Algebra/Lie/Submodule.lean @@ -838,7 +838,7 @@ theorem comap_incl_eq_bot : N₂.comap N.incl = ⊥ ↔ N ⊓ N₂ = ⊥ := by inf_coe_toSubmodule] rw [← Submodule.disjoint_iff_comap_eq_bot, disjoint_iff] -@[mono] +@[gcongr, mono] theorem map_mono (h : N ≤ N₂) : N.map f ≤ N₂.map f := Set.image_subset _ h @@ -1209,15 +1209,9 @@ lemma incl_injective (I : LieIdeal R L) : Function.Injective I.incl := @[simp] theorem comap_incl_self : comap I.incl I = ⊤ := by ext; simp - -- porting note: `ext; simp` works also in mathlib3, though the proof used to be - -- rw [← LieSubmodule.coe_toSubmodule_eq_iff, LieSubmodule.top_coeSubmodule, - -- LieIdeal.comap_coeSubmodule, LieIdeal.incl_coe, Submodule.comap_subtype_self] @[simp] theorem ker_incl : I.incl.ker = ⊥ := by ext; simp - -- porting note: `ext; simp` works also in mathlib3, though the proof used to be - -- rw [← LieSubmodule.coe_toSubmodule_eq_iff, I.incl.ker_coeSubmodule, - -- LieSubmodule.bot_coeSubmodule, incl_coe, Submodule.ker_subtype] @[simp] theorem incl_idealRange : I.incl.idealRange = I := by diff --git a/Mathlib/Algebra/Lie/Weights/Chain.lean b/Mathlib/Algebra/Lie/Weights/Chain.lean index 1acfd102224c7..cc0efd7803997 100644 --- a/Mathlib/Algebra/Lie/Weights/Chain.lean +++ b/Mathlib/Algebra/Lie/Weights/Chain.lean @@ -132,8 +132,11 @@ lemma lie_mem_genWeightSpaceChain_of_genWeightSpace_eq_bot_right [LieAlgebra.IsN obtain ⟨k, hk⟩ := k suffices genWeightSpace M ((k + 1) • α + χ) ≤ genWeightSpaceChain M α χ p q by apply this - simpa using (rootSpaceWeightSpaceProduct R L H M α (k • α + χ) ((k + 1) • α + χ) - (by rw [add_smul]; abel) (⟨x, hx⟩ ⊗ₜ ⟨z, hz⟩)).property + -- was `simpa using [...]` and very slow + -- (https://github.com/leanprover-community/mathlib4/issues/19751) + simpa only [zsmul_eq_mul, Int.cast_add, Pi.intCast_def, Int.cast_one] using + (rootSpaceWeightSpaceProduct R L H M α (k • α + χ) ((k + 1) • α + χ) + (by rw [add_smul]; abel) (⟨x, hx⟩ ⊗ₜ ⟨z, hz⟩)).property rw [genWeightSpaceChain] rcases eq_or_ne (k + 1) q with rfl | hk'; · simp only [hq, bot_le] replace hk' : k + 1 ∈ Ioo p q := ⟨by linarith [hk.1], lt_of_le_of_ne hk.2 hk'⟩ @@ -210,19 +213,19 @@ lemma exists_forall_mem_corootSpace_smul_add_eq_zero exact SetCoe.ext <| smul_left_injective ℤ hα <| by rwa [add_left_inj] at hij have h₂ : ∀ i, MapsTo (toEnd R H M x) ↑(N i) ↑(N i) := fun _ _ ↦ LieSubmodule.lie_mem _ have h₃ : genWeightSpaceChain M α χ p q = ⨆ i ∈ Finset.Ioo p q, N i := by - simp_rw [genWeightSpaceChain_def', LieSubmodule.iSup_coe_toSubmodule] + simp_rw [N, genWeightSpaceChain_def', LieSubmodule.iSup_coe_toSubmodule] rw [← trace_toEnd_genWeightSpaceChain_eq_zero M α χ p q hp hq hx, ← LieSubmodule.toEnd_restrict_eq_toEnd] -- The lines below illustrate the cost of treating `LieSubmodule` as both a -- `Submodule` and a `LieSubmodule` simultaneously. erw [LinearMap.trace_eq_sum_trace_restrict_of_eq_biSup _ h₁ h₂ (genWeightSpaceChain M α χ p q) h₃] - simp_rw [LieSubmodule.toEnd_restrict_eq_toEnd] + simp_rw [N, LieSubmodule.toEnd_restrict_eq_toEnd] dsimp [N] convert_to _ = ∑ k ∈ Finset.Ioo p q, (LinearMap.trace R { x // x ∈ (genWeightSpace M (k • α + χ)) }) ((toEnd R { x // x ∈ H } { x // x ∈ genWeightSpace M (k • α + χ) }) x) - simp_rw [trace_toEnd_genWeightSpace, Pi.add_apply, Pi.smul_apply, smul_add, ← smul_assoc, - Finset.sum_add_distrib, ← Finset.sum_smul, natCast_zsmul] + simp_rw [a, b, trace_toEnd_genWeightSpace, Pi.add_apply, Pi.smul_apply, smul_add, + ← smul_assoc, Finset.sum_add_distrib, ← Finset.sum_smul, natCast_zsmul] end IsCartanSubalgebra diff --git a/Mathlib/Algebra/Lie/Weights/Killing.lean b/Mathlib/Algebra/Lie/Weights/Killing.lean index 7c2b6ece5a6b5..a4667d0fba6aa 100644 --- a/Mathlib/Algebra/Lie/Weights/Killing.lean +++ b/Mathlib/Algebra/Lie/Weights/Killing.lean @@ -298,7 +298,7 @@ lemma isSemisimple_ad_of_mem_isCartanSubalgebra {x : L} (hx : x ∈ H) : /- `y` commutes with all elements of `H` because `S` has eigenvalue 0 on `H`, `S = ad K L y`. -/ have hy' (z : L) (hz : z ∈ H) : ⁅y, z⁆ = 0 := by rw [← LieSubalgebra.mem_toLieSubmodule, ← rootSpace_zero_eq] at hz - simp [← ad_apply (R := K), ← LieDerivation.coe_ad_apply_eq_ad_apply, hy, aux hz] + simp [S', ← ad_apply (R := K), ← LieDerivation.coe_ad_apply_eq_ad_apply, hy, aux hz] /- Thus `y` belongs to `H` since `H` is self-normalizing. -/ replace hy' : y ∈ H := by suffices y ∈ H.normalizer by rwa [LieSubalgebra.IsCartanSubalgebra.self_normalizing] at this @@ -489,7 +489,7 @@ lemma exists_isSl2Triple_of_weight_isNonZero {α : Weight K H L} (hα : α.IsNon let h : H := ⟨⁅e, f'⁆, hef ▸ Submodule.smul_mem _ _ (Submodule.coe_mem _)⟩ have hh : α h ≠ 0 := by have : h = killingForm K L e f' • (cartanEquivDual H).symm α := by - simp only [Subtype.ext_iff, hef] + simp only [h, Subtype.ext_iff, hef] rw [Submodule.coe_smul_of_tower] rw [this, map_smul, smul_eq_mul, ne_eq, mul_eq_zero, not_or] exact ⟨hf, root_apply_cartanEquivDual_symm_ne_zero hα⟩ diff --git a/Mathlib/Algebra/Lie/Weights/RootSystem.lean b/Mathlib/Algebra/Lie/Weights/RootSystem.lean index d2a8a94210cd9..c6334632c472d 100644 --- a/Mathlib/Algebra/Lie/Weights/RootSystem.lean +++ b/Mathlib/Algebra/Lie/Weights/RootSystem.lean @@ -407,9 +407,9 @@ alias rootSystem_toLin_apply := rootSystem_toPerfectPairing_apply @[simp] lemma rootSystem_root_apply (α) : (rootSystem H).root α = α := rfl @[simp] lemma rootSystem_coroot_apply (α) : (rootSystem H).coroot α = coroot α := rfl -theorem isCrystallographic_rootSystem : (rootSystem H).IsCrystallographic := by - rintro α _ ⟨β, rfl⟩ - exact ⟨chainBotCoeff β.1 α.1 - chainTopCoeff β.1 α.1, by simp [apply_coroot_eq_cast β.1 α.1]⟩ +instance : (rootSystem H).IsCrystallographic where + exists_int α β := + ⟨chainBotCoeff β.1 α.1 - chainTopCoeff β.1 α.1, by simp [apply_coroot_eq_cast β.1 α.1]⟩ theorem isReduced_rootSystem : (rootSystem H).IsReduced := by intro ⟨α, hα⟩ ⟨β, hβ⟩ e diff --git a/Mathlib/Algebra/LinearRecurrence.lean b/Mathlib/Algebra/LinearRecurrence.lean index 86fe25eb54450..696a59e766aa7 100644 --- a/Mathlib/Algebra/LinearRecurrence.lean +++ b/Mathlib/Algebra/LinearRecurrence.lean @@ -96,7 +96,6 @@ theorem eq_mk_of_is_sol_of_eq_init {u : ℕ → α} {init : Fin E.order → α} rw [mkSol] split_ifs with h' · exact mod_cast heq ⟨n, h'⟩ - simp only rw [← tsub_add_cancel_of_le (le_of_not_lt h'), h (n - E.order)] congr with k have : n - E.order + k < n := by diff --git a/Mathlib/Algebra/Module/End.lean b/Mathlib/Algebra/Module/End.lean index 405cb931c87f9..426b42dfa3ea6 100644 --- a/Mathlib/Algebra/Module/End.lean +++ b/Mathlib/Algebra/Module/End.lean @@ -57,9 +57,20 @@ def smulAddHom : R →+ M →+ M := variable {R M} @[simp] -theorem smulAddHom_apply (r : R) (x : M) : smulAddHom R M r x = r • x := +theorem smulAddHom_apply : smulAddHom R M r x = r • x := rfl +variable {x} + +lemma IsAddUnit.smul_left [Monoid S] [DistribMulAction S M] (hx : IsAddUnit x) (s : S) : + IsAddUnit (s • x) := + hx.map (DistribMulAction.toAddMonoidHom M s) + +variable {r} (x) + +lemma IsAddUnit.smul_right (hr : IsAddUnit r) : IsAddUnit (r • x) := + hr.map (AddMonoidHom.flip (smulAddHom R M) x) + end AddCommMonoid section AddCommGroup @@ -81,6 +92,7 @@ section variable (R) /-- `zsmul` is equal to any other module structure via a cast. -/ +@[norm_cast] lemma Int.cast_smul_eq_zsmul (n : ℤ) (b : M) : (n : R) • b = n • b := have : ((smulAddHom R M).flip b).comp (Int.castAddHom R) = (smulAddHom ℤ M).flip b := by apply AddMonoidHom.ext_int diff --git a/Mathlib/Algebra/Module/Equiv/Basic.lean b/Mathlib/Algebra/Module/Equiv/Basic.lean index 67ae9340c5ef4..1ccd71d6cbcbb 100644 --- a/Mathlib/Algebra/Module/Equiv/Basic.lean +++ b/Mathlib/Algebra/Module/Equiv/Basic.lean @@ -96,6 +96,8 @@ theorem coe_pow (e : M ≃ₗ[R] M) (n : ℕ) : ⇑(e ^ n) = e^[n] := hom_coe_po theorem pow_apply (e : M ≃ₗ[R] M) (n : ℕ) (m : M) : (e ^ n) m = e^[n] m := congr_fun (coe_pow e n) m +@[simp] lemma mul_apply (f : M ≃ₗ[R] M) (g : M ≃ₗ[R] M) (x : M) : (f * g) x = f (g x) := rfl + /-- Restriction from `R`-linear automorphisms of `M` to `R`-linear endomorphisms of `M`, promoted to a monoid hom. -/ @[simps] diff --git a/Mathlib/Algebra/Module/FinitePresentation.lean b/Mathlib/Algebra/Module/FinitePresentation.lean index b5737ac1b8e49..468b2cc116e18 100644 --- a/Mathlib/Algebra/Module/FinitePresentation.lean +++ b/Mathlib/Algebra/Module/FinitePresentation.lean @@ -373,7 +373,7 @@ lemma exists_bijective_map_powers [Module.Finite R M] [Module.FinitePresentation simp only [Module.algebraMap_end_apply, algebraMap_smul, LinearMap.map_smul_of_tower] rw [LinearMap.smul_comp, ← smul_assoc s₀.1, Algebra.smul_def s₀.1, IsUnit.mul_val_inv, one_smul] apply LinearMap.restrictScalars_injective R - apply IsLocalizedModule.ringHom_ext (.powers t) (LocalizedModule.mkLinearMap (.powers t) M) + apply IsLocalizedModule.ext (.powers t) (LocalizedModule.mkLinearMap (.powers t) M) (IsLocalizedModule.map_units (LocalizedModule.mkLinearMap (.powers t) M)) ext x have : s₂.1 • l' (l x) = s₂.1 • s₀.1 • x := congr($hs₂ x) @@ -384,7 +384,7 @@ lemma exists_bijective_map_powers [Module.Finite R M] [Module.FinitePresentation simp only [Module.algebraMap_end_apply, algebraMap_smul, LinearMap.map_smul_of_tower] rw [LinearMap.comp_smul, ← smul_assoc s₀.1, Algebra.smul_def s₀.1, IsUnit.mul_val_inv, one_smul] apply LinearMap.restrictScalars_injective R - apply IsLocalizedModule.ringHom_ext (.powers t) (LocalizedModule.mkLinearMap (.powers t) N) + apply IsLocalizedModule.ext (.powers t) (LocalizedModule.mkLinearMap (.powers t) N) (IsLocalizedModule.map_units (LocalizedModule.mkLinearMap (.powers t) N)) ext x have : s₁.1 • l (l' x) = s₁.1 • s₀.1 • x := congr($hs₁ x) @@ -415,7 +415,7 @@ lemma Module.FinitePresentation.exists_lift_equiv_of_isLocalizedModule obtain ⟨l', s, H⟩ := Module.FinitePresentation.exists_lift_of_isLocalizedModule S g (l ∘ₗ f) have : Function.Bijective (IsLocalizedModule.map S f g l') := by have : IsLocalizedModule.map S f g l' = (s • LinearMap.id) ∘ₗ l := by - apply IsLocalizedModule.ringHom_ext S f (IsLocalizedModule.map_units g) + apply IsLocalizedModule.ext S f (IsLocalizedModule.map_units g) apply LinearMap.ext fun x ↦ ?_ simp only [LinearMap.coe_comp, Function.comp_apply, IsLocalizedModule.map_apply, Basis.coe_repr_symm, LinearMap.coe_restrictScalars] @@ -433,12 +433,12 @@ lemma Module.FinitePresentation.exists_lift_equiv_of_isLocalizedModule ((Module.End_isUnit_iff _).mp ((hsu.unit⁻¹).isUnit.map (algebraMap _ (End Rᵣₛ (LocalizedModule rs N))))).comp (hr' (r * s) (dvd_mul_right _ _)) refine ⟨r * s, mul_mem hr s.2, LinearEquiv.ofBijective _ this, ?_⟩ - apply IsLocalizedModule.ringHom_ext rs (LocalizedModule.mkLinearMap rs M) fun x ↦ map_units g + apply IsLocalizedModule.ext rs (LocalizedModule.mkLinearMap rs M) fun x ↦ map_units g ⟨x.1, SetLike.le_def.mp (Submonoid.powers_le.mpr (mul_mem hr s.2)) x.2⟩ ext x apply ((Module.End_isUnit_iff _).mp (IsLocalizedModule.map_units g s)).1 have : ∀ x, g (l' x) = s.1 • (l (f x)) := LinearMap.congr_fun H - simp only [LinearMap.coe_comp, LinearMap.coe_restrictScalars, LinearEquiv.coe_coe, + simp only [rs, LinearMap.coe_comp, LinearMap.coe_restrictScalars, LinearEquiv.coe_coe, Function.comp_apply, LocalizedModule.mkLinearMap_apply, LinearEquiv.ofBijective_apply, LinearMap.smul_apply, LocalizedModule.map_mk, algebraMap_end_apply] rw [← map_smul, ← smul_assoc, Algebra.smul_def s.1, hsu.mul_val_inv, one_smul] @@ -461,7 +461,7 @@ instance Module.FinitePresentation.isLocalizedModule_map [Module.FinitePresentat · intro h obtain ⟨h', s, e⟩ := Module.FinitePresentation.exists_lift_of_isLocalizedModule S g (h ∘ₗ f) refine ⟨⟨h', s⟩, ?_⟩ - apply IsLocalizedModule.ringHom_ext S f (IsLocalizedModule.map_units g) + apply IsLocalizedModule.ext S f (IsLocalizedModule.map_units g) refine e.symm.trans (by ext; simp) · intro h₁ h₂ e apply Module.Finite.exists_smul_of_comp_eq_of_isLocalizedModule S g diff --git a/Mathlib/Algebra/Module/FreeLocus.lean b/Mathlib/Algebra/Module/FreeLocus.lean index 9f42786132f02..770e2b8cab031 100644 --- a/Mathlib/Algebra/Module/FreeLocus.lean +++ b/Mathlib/Algebra/Module/FreeLocus.lean @@ -10,6 +10,7 @@ import Mathlib.RingTheory.LocalRing.Module import Mathlib.RingTheory.Localization.Free import Mathlib.RingTheory.Localization.LocalizationLocalization import Mathlib.Topology.LocallyConstant.Basic +import Mathlib.RingTheory.TensorProduct.Free /-! @@ -88,10 +89,10 @@ lemma comap_freeLocus_le {A} [CommRing A] [Algebra R A] : let Aₚ := Localization.AtPrime p.asIdeal rw [Set.mem_preimage, mem_freeLocus_iff_tensor _ Rₚ] at hp rw [mem_freeLocus_iff_tensor _ Aₚ] - letI : Algebra Rₚ Aₚ := (Localization.localRingHom + letI algebra : Algebra Rₚ Aₚ := (Localization.localRingHom (comap (algebraMap R A) p).asIdeal p.asIdeal (algebraMap R A) rfl).toAlgebra have : IsScalarTower R Rₚ Aₚ := IsScalarTower.of_algebraMap_eq' - (by simp [RingHom.algebraMap_toAlgebra, Localization.localRingHom, + (by simp [Rₚ, Aₚ, algebra, RingHom.algebraMap_toAlgebra, Localization.localRingHom, ← IsScalarTower.algebraMap_eq]) let e := AlgebraTensorModule.cancelBaseChange R Rₚ Aₚ Aₚ M ≪≫ₗ (AlgebraTensorModule.cancelBaseChange R A Aₚ Aₚ M).symm @@ -124,9 +125,9 @@ lemma freeLocus_localization (S : Submonoid R) : letI : Module (Localization S) Mₚ := Module.compHom Mₚ (algebraMap _ Rₚ) have : IsScalarTower R (Localization S) Mₚ := ⟨fun r r' m ↦ show algebraMap _ Rₚ (r • r') • m = _ by - simp [Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ + simp [p', Rₚ, Mₚ, Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ have : IsScalarTower (Localization S) Rₚ Mₚ := - ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • _ by rw [← mul_smul, ← Algebra.smul_def]⟩ + ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • r' • m by rw [← mul_smul, ← Algebra.smul_def]⟩ let l := (IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap S M) (LocalizedModule.mkLinearMap p'.primeCompl M)).extendScalarsOfIsLocalization S (Localization S) @@ -201,9 +202,9 @@ lemma isLocallyConstant_rankAtStalk_freeLocus [Module.FinitePresentation R M] : letI : Module (Localization.Away f) Mₚ := Module.compHom Mₚ (algebraMap _ Rₚ) have : IsScalarTower R (Localization.Away f) Mₚ := ⟨fun r r' m ↦ show algebraMap _ Rₚ (r • r') • m = _ by - simp [Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ + simp [Rₚ, Mₚ, Algebra.smul_def, ← IsScalarTower.algebraMap_apply, mul_smul]; rfl⟩ have : IsScalarTower (Localization.Away f) Rₚ Mₚ := - ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • _ by rw [← mul_smul, ← Algebra.smul_def]⟩ + ⟨fun r r' m ↦ show _ = algebraMap _ Rₚ r • r' • m by rw [← mul_smul, ← Algebra.smul_def]⟩ let l := (IsLocalizedModule.liftOfLE _ _ hp' (LocalizedModule.mkLinearMap (.powers f) M) (LocalizedModule.mkLinearMap p.asIdeal.primeCompl M)).extendScalarsOfIsLocalization (.powers f) (Localization.Away f) diff --git a/Mathlib/Algebra/Module/LinearMap/Polynomial.lean b/Mathlib/Algebra/Module/LinearMap/Polynomial.lean index 3a315ebcd1b5c..5637e7a41bdf3 100644 --- a/Mathlib/Algebra/Module/LinearMap/Polynomial.lean +++ b/Mathlib/Algebra/Module/LinearMap/Polynomial.lean @@ -548,12 +548,12 @@ lemma exists_isNilRegular_of_finrank_le_card (h : finrank R M ≤ #R) : have aux : ((polyCharpoly φ b).coeff (nilRank φ)).IsHomogeneous (n - nilRank φ) := polyCharpoly_coeff_isHomogeneous _ b (nilRank φ) (n - nilRank φ) - (by simp [nilRank_le_card φ bₘ, finrank_eq_card_chooseBasisIndex]) + (by simp [n, nilRank_le_card φ bₘ, finrank_eq_card_chooseBasisIndex]) obtain ⟨x, hx⟩ : ∃ r, eval r ((polyCharpoly _ b).coeff (nilRank φ)) ≠ 0 := by by_contra! h₀ apply polyCharpoly_coeff_nilRank_ne_zero φ b apply aux.eq_zero_of_forall_eval_eq_zero_of_le_card h₀ (le_trans _ h) - simp only [finrank_eq_card_chooseBasisIndex, Nat.cast_le, Nat.sub_le] + simp only [n, finrank_eq_card_chooseBasisIndex, Nat.cast_le, Nat.sub_le] let c := Finsupp.equivFunOnFinite.symm x use b.repr.symm c rwa [isNilRegular_iff_coeff_polyCharpoly_nilRank_ne_zero _ b, LinearEquiv.apply_symm_apply] diff --git a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean index efe62ee72caee..3cdf9bb43a356 100644 --- a/Mathlib/Algebra/Module/LocalizedModule/Basic.lean +++ b/Mathlib/Algebra/Module/LocalizedModule/Basic.lean @@ -914,11 +914,19 @@ theorem is_universal : ∃! l : M' →ₗ[R] M'', l.comp f = g := fun g h => ⟨lift S f g h, lift_comp S f g h, fun l hl => (lift_unique S f g h l hl).symm⟩ -theorem ringHom_ext (map_unit : ∀ x : S, IsUnit ((algebraMap R (Module.End R M'')) x)) +theorem linearMap_ext {N N'} [AddCommMonoid N] [Module R N] [AddCommMonoid N'] [Module R N'] + (f' : N →ₗ[R] N') [IsLocalizedModule S f'] ⦃g g' : M' →ₗ[R] N'⦄ + (h : g ∘ₗ f = g' ∘ₗ f) : g = g' := + (is_universal S f _ <| map_units f').unique h rfl + +theorem ext (map_unit : ∀ x : S, IsUnit ((algebraMap R (Module.End R M'')) x)) ⦃j k : M' →ₗ[R] M''⦄ (h : j.comp f = k.comp f) : j = k := by rw [← lift_unique S f (k.comp f) map_unit j h, lift_unique] rfl +@[deprecated (since := "2024-12-07")] +alias ringHom_ext := ext + /-- If `(M', f)` and `(M'', g)` both satisfy universal property of localized module, then `M', M''` are isomorphic as `R`-module -/ @@ -1110,10 +1118,10 @@ noncomputable def map : (M →ₗ[R] N) →ₗ[R] (M' →ₗ[R] N') where toFun h := lift S f (g ∘ₗ h) (IsLocalizedModule.map_units g) map_add' h₁ h₂ := by - apply IsLocalizedModule.ringHom_ext S f (IsLocalizedModule.map_units g) + apply IsLocalizedModule.ext S f (IsLocalizedModule.map_units g) simp only [lift_comp, LinearMap.add_comp, LinearMap.comp_add] map_smul' r h := by - apply IsLocalizedModule.ringHom_ext S f (IsLocalizedModule.map_units g) + apply IsLocalizedModule.ext S f (IsLocalizedModule.map_units g) simp only [lift_comp, LinearMap.add_comp, LinearMap.comp_add, LinearMap.smul_comp, LinearMap.comp_smul, RingHom.id_apply] diff --git a/Mathlib/Algebra/Module/NatInt.lean b/Mathlib/Algebra/Module/NatInt.lean index d1aab097a652d..22860f1391265 100644 --- a/Mathlib/Algebra/Module/NatInt.lean +++ b/Mathlib/Algebra/Module/NatInt.lean @@ -95,6 +95,7 @@ section variable (R) /-- `nsmul` is equal to any other module structure via a cast. -/ +@[norm_cast] lemma Nat.cast_smul_eq_nsmul (n : ℕ) (b : M) : (n : R) • b = n • b := by induction n with | zero => rw [Nat.cast_zero, zero_smul, zero_smul] diff --git a/Mathlib/Algebra/Module/Presentation/RestrictScalars.lean b/Mathlib/Algebra/Module/Presentation/RestrictScalars.lean new file mode 100644 index 0000000000000..108320b3d56d8 --- /dev/null +++ b/Mathlib/Algebra/Module/Presentation/RestrictScalars.lean @@ -0,0 +1,66 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.Algebra.Module.Presentation.DirectSum +import Mathlib.Algebra.Module.Presentation.Cokernel + +/-! +# Presentation of the restriction of scalars of a module + +Given a morphism of rings `A → B` and a `B`-module `M`, we obtain a presentation +of `M` as a `A`-module from a presentation of `M` as `B`-module, +a presentation of `B` as a `A`-module (and some additional data). + +## TODO +* deduce that if `B` is a finitely presented as an `A`-module and `M` is +finitely presented as an `B`-module, then `M` is finitely presented as an `A`-module + +-/ + +namespace Module + +variable {B : Type*} [Ring B] {M : Type*} [AddCommGroup M] [Module B M] + [DecidableEq B] + (presM : Presentation B M) [DecidableEq presM.G] + {A : Type*} [CommRing A] [Algebra A B] [Module A M] [IsScalarTower A B M] + (presB : Presentation A B) + +namespace Presentation + +/-- The additional data that is necessary in order to obtain a presentation +of the restriction of scalars of a module. -/ +abbrev RestrictScalarsData : Type _ := + (presB.finsupp presM.G).CokernelData + (LinearMap.restrictScalars A presM.map) + (fun (⟨g, g'⟩ : presB.G × presM.R) ↦ presB.var g • Finsupp.single g' (1 : B)) + +variable (data : presM.RestrictScalarsData presB) + +/-- A presentation of the restriction of scalars from `B` to `A` of a `B`-module `M`, +given a presentation of `M` as a `B`-module, a presentation of `B` as an `A`-module, +and an additional data. -/ +noncomputable def restrictScalars : Presentation A M := + ofExact (g := LinearMap.restrictScalars A presM.π) (presB.finsupp presM.G) data + presM.exact presM.surjective_π (by + ext v + dsimp + simp only [Submodule.mem_top, iff_true] + apply Finsupp.induction + · simp + · intro r b w _ _ hw + refine Submodule.add_mem _ ?_ hw + obtain ⟨β, rfl⟩ := presB.surjective_π b + apply Finsupp.induction (p := fun β ↦ Finsupp.single r (presB.π β) ∈ _) + · simp + · intro g a f _ _ hf + rw [map_add, Finsupp.single_add] + refine Submodule.add_mem _ ?_ hf + rw [← Finsupp.smul_single_one, ← Finsupp.smul_single_one, + map_smul, Relations.Solution.π_single, smul_assoc] + exact Submodule.smul_mem _ _ (Submodule.subset_span ⟨⟨g, r⟩, rfl⟩)) + +end Presentation + +end Module diff --git a/Mathlib/Algebra/Module/Submodule/Basic.lean b/Mathlib/Algebra/Module/Submodule/Basic.lean index 05f1f2a66fbab..e6ab0afbfd51c 100644 --- a/Mathlib/Algebra/Module/Submodule/Basic.lean +++ b/Mathlib/Algebra/Module/Submodule/Basic.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Nathaniel Thomas, Jeremy Avigad, Johannes Hölzl, Mario Carneiro -/ import Mathlib.Algebra.Field.Defs -import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Module.Submodule.Defs import Mathlib.Algebra.NoZeroSMulDivisors.Defs import Mathlib.GroupTheory.GroupAction.SubMulAction diff --git a/Mathlib/Algebra/Module/Submodule/Bilinear.lean b/Mathlib/Algebra/Module/Submodule/Bilinear.lean index 1564df8114cd7..0f4c48b6a1522 100644 --- a/Mathlib/Algebra/Module/Submodule/Bilinear.lean +++ b/Mathlib/Algebra/Module/Submodule/Bilinear.lean @@ -84,7 +84,7 @@ theorem map₂_bot_left (f : M →ₗ[R] N →ₗ[R] P) (q : Submodule R N) : ma rw [Submodule.mem_bot] at hm ⊢ rw [hm, LinearMap.map_zero₂] -@[mono] +@[gcongr, mono] theorem map₂_le_map₂ {f : M →ₗ[R] N →ₗ[R] P} {p₁ p₂ : Submodule R M} {q₁ q₂ : Submodule R N} (hp : p₁ ≤ p₂) (hq : q₁ ≤ q₂) : map₂ f p₁ q₁ ≤ map₂ f p₂ q₂ := map₂_le.2 fun _m hm _n hn => apply_mem_map₂ _ (hp hm) (hq hn) diff --git a/Mathlib/Algebra/Module/Submodule/Invariant.lean b/Mathlib/Algebra/Module/Submodule/Invariant.lean index 0e8d20eb33819..cfb3ce8b980af 100644 --- a/Mathlib/Algebra/Module/Submodule/Invariant.lean +++ b/Mathlib/Algebra/Module/Submodule/Invariant.lean @@ -13,7 +13,7 @@ In this file we defined the type `Module.End.invtSubmodule`, associated to a lin a module. Its utilty stems primarily from those occasions on which we wish to take advantage of the lattice structure of invariant submodules. -See also `Module.AEval`. +See also `Mathlib.Algebra.Polynomial.Module.AEval`. -/ diff --git a/Mathlib/Algebra/Module/Submodule/Lattice.lean b/Mathlib/Algebra/Module/Submodule/Lattice.lean index 76744e1fa2be2..364a656683578 100644 --- a/Mathlib/Algebra/Module/Submodule/Lattice.lean +++ b/Mathlib/Algebra/Module/Submodule/Lattice.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Mario Carneiro, Kevin Buzzard, Yury Kudryashov -/ import Mathlib.Algebra.Group.Subgroup.Lattice import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Module.Submodule.Defs import Mathlib.Algebra.Module.Equiv.Defs import Mathlib.Algebra.PUnitInstances.Module diff --git a/Mathlib/Algebra/Module/Submodule/Pointwise.lean b/Mathlib/Algebra/Module/Submodule/Pointwise.lean index 99f269138c452..45fc65acdabe9 100644 --- a/Mathlib/Algebra/Module/Submodule/Pointwise.lean +++ b/Mathlib/Algebra/Module/Submodule/Pointwise.lean @@ -3,11 +3,10 @@ Copyright (c) 2021 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser, Jujian Zhang -/ -import Mathlib.Algebra.Module.BigOperators import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Order.Group.Action -import Mathlib.RingTheory.Ideal.Span -import Mathlib.LinearAlgebra.Finsupp.LinearCombination +import Mathlib.LinearAlgebra.Finsupp.Supported +import Mathlib.LinearAlgebra.Span.Basic /-! # Pointwise instances on `Submodule`s @@ -39,6 +38,7 @@ Other than section `set_acting_on_submodules`, most of the lemmas in this file a lemmas from the file `Mathlib.Algebra.Group.Submonoid.Pointwise`. -/ +assert_not_exists Ideal variable {α : Type*} {R : Type*} {M : Type*} @@ -526,33 +526,6 @@ lemma sup_set_smul (s t : Set S) : · 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 - | mem _ h => exact mem_set_smul_of_mem_mem h hn - | zero => rw [zero_smul]; exact Submodule.zero_mem _ - | add _ _ _ _ ihr ihs => rw [add_smul]; exact Submodule.add_mem _ ihr ihs - | smul _ _ hr => - 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 -lemma span_singleton_toAddSubgroup_eq_zmultiples (a : ℤ) : - (span ℤ {a}).toAddSubgroup = AddSubgroup.zmultiples a := by - ext i - simp [Ideal.mem_span_singleton', AddSubgroup.mem_zmultiples_iff] - end Submodule - -@[simp] lemma Ideal.span_singleton_toAddSubgroup_eq_zmultiples (a : ℤ) : - (Ideal.span {a}).toAddSubgroup = AddSubgroup.zmultiples a := - Submodule.span_singleton_toAddSubgroup_eq_zmultiples _ diff --git a/Mathlib/Algebra/Module/ZLattice/Basic.lean b/Mathlib/Algebra/Module/ZLattice/Basic.lean index cadfde60a1179..b8b6b0b57e2f6 100644 --- a/Mathlib/Algebra/Module/ZLattice/Basic.lean +++ b/Mathlib/Algebra/Module/ZLattice/Basic.lean @@ -62,11 +62,17 @@ variable (b : Basis ι K E) theorem span_top : span K (span ℤ (Set.range b) : Set E) = ⊤ := by simp [span_span_of_tower] - theorem map {F : Type*} [NormedAddCommGroup F] [NormedSpace K F] (f : E ≃ₗ[K] F) : Submodule.map (f.restrictScalars ℤ) (span ℤ (Set.range b)) = span ℤ (Set.range (b.map f)) := by simp_rw [Submodule.map_span, LinearEquiv.restrictScalars_apply, Basis.coe_map, Set.range_comp] +open scoped Pointwise in +theorem smul {c : K} (hc : c ≠ 0) : + c • span ℤ (Set.range b) = span ℤ (Set.range (b.isUnitSMul (fun _ ↦ hc.isUnit))) := by + rw [smul_span, Set.smul_set_range] + congr! + rw [Basis.isUnitSMul_apply] + /-- The fundamental domain of the ℤ-lattice spanned by `b`. See `ZSpan.isAddFundamentalDomain` for the proof that it is a fundamental domain. -/ def fundamentalDomain : Set E := {m | ∀ i, b.repr m i ∈ Set.Ico (0 : K) 1} @@ -309,6 +315,13 @@ instance [Finite ι] : DiscreteTopology (span ℤ (Set.range b)) := by instance [Finite ι] : DiscreteTopology (span ℤ (Set.range b)).toAddSubgroup := inferInstanceAs <| DiscreteTopology (span ℤ (Set.range b)) +theorem setFinite_inter [ProperSpace E] [Finite ι] {s : Set E} (hs : Bornology.IsBounded s) : + Set.Finite (s ∩ span ℤ (Set.range b)) := by + have : DiscreteTopology (span ℤ (Set.range b)) := inferInstance + refine Metric.finite_isBounded_inter_isClosed hs ?_ + change IsClosed ((span ℤ (Set.range b)).toAddSubgroup : Set E) + exact AddSubgroup.isClosed_of_discrete + @[measurability] theorem fundamentalDomain_measurableSet [MeasurableSpace E] [OpensMeasurableSpace E] [Finite ι] : MeasurableSet (fundamentalDomain b) := by diff --git a/Mathlib/Algebra/MonoidAlgebra/Defs.lean b/Mathlib/Algebra/MonoidAlgebra/Defs.lean index 41e3c6d67e134..da1c6d0c0a369 100644 --- a/Mathlib/Algebra/MonoidAlgebra/Defs.lean +++ b/Mathlib/Algebra/MonoidAlgebra/Defs.lean @@ -345,6 +345,10 @@ variable {S : Type*} instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R (MonoidAlgebra k G) := Finsupp.smulZeroClass +instance noZeroSMulDivisors [Zero R] [Semiring k] [SMulZeroClass R k] [NoZeroSMulDivisors R k] : + NoZeroSMulDivisors R (MonoidAlgebra k G) := + Finsupp.noZeroSMulDivisors + instance distribSMul [Semiring k] [DistribSMul R k] : DistribSMul R (MonoidAlgebra k G) := Finsupp.distribSMul _ _ @@ -1063,6 +1067,10 @@ section Semiring instance smulZeroClass [Semiring k] [SMulZeroClass R k] : SMulZeroClass R k[G] := Finsupp.smulZeroClass +instance noZeroSMulDivisors [Zero R] [Semiring k] [SMulZeroClass R k] [NoZeroSMulDivisors R k] : + NoZeroSMulDivisors R k[G] := + Finsupp.noZeroSMulDivisors + variable [Semiring k] [AddMonoid G] instance semiring : Semiring k[G] := diff --git a/Mathlib/Algebra/MvPolynomial/Degrees.lean b/Mathlib/Algebra/MvPolynomial/Degrees.lean index 9dd0aa38991a3..5227f6ddbbe60 100644 --- a/Mathlib/Algebra/MvPolynomial/Degrees.lean +++ b/Mathlib/Algebra/MvPolynomial/Degrees.lean @@ -282,25 +282,41 @@ theorem degreeOf_pow_le (i : σ) (p : MvPolynomial σ R) (n : ℕ) : degreeOf i (p ^ n) ≤ n * degreeOf i p := by simpa using degreeOf_prod_le i (Finset.range n) (fun _ => p) -theorem degreeOf_mul_X_ne {i j : σ} (f : MvPolynomial σ R) (h : i ≠ j) : +theorem degreeOf_mul_X_of_ne {i j : σ} (f : MvPolynomial σ R) (h : i ≠ j) : degreeOf i (f * X j) = degreeOf i f := by classical simp only [degreeOf_eq_sup i, support_mul_X, Finset.sup_map] congr ext - simp only [Finsupp.single, Nat.one_ne_zero, add_right_eq_self, addRightEmbedding_apply, coe_mk, + simp only [Finsupp.single, add_right_eq_self, addRightEmbedding_apply, coe_mk, Pi.add_apply, comp_apply, ite_eq_right_iff, Finsupp.coe_add, Pi.single_eq_of_ne h] --- TODO in the following we have equality iff `f ≠ 0` -theorem degreeOf_mul_X_eq (j : σ) (f : MvPolynomial σ R) : +@[deprecated (since := "2024-12-01")] alias degreeOf_mul_X_ne := degreeOf_mul_X_of_ne + +theorem degreeOf_mul_X_self (j : σ) (f : MvPolynomial σ R) : degreeOf j (f * X j) ≤ degreeOf j f + 1 := by classical simp only [degreeOf] apply (Multiset.count_le_of_le j (degrees_mul f (X j))).trans simp only [Multiset.count_add, add_le_add_iff_left] - convert Multiset.count_le_of_le j (degrees_X' (R := R) j) + convert Multiset.count_le_of_le j <| degrees_X' j rw [Multiset.count_singleton_self] +@[deprecated (since := "2024-12-01")] alias degreeOf_mul_X_eq := degreeOf_mul_X_self + +theorem degreeOf_mul_X_eq_degreeOf_add_one_iff (j : σ) (f : MvPolynomial σ R) : + degreeOf j (f * X j) = degreeOf j f + 1 ↔ f ≠ 0 := by + refine ⟨fun h => by by_contra ha; simp [ha] at h, fun h => ?_⟩ + apply Nat.le_antisymm (degreeOf_mul_X_self j f) + have : (f.support.sup fun m ↦ m j) + 1 = (f.support.sup fun m ↦ (m j + 1)) := + Finset.comp_sup_eq_sup_comp_of_nonempty @Nat.succ_le_succ (support_nonempty.mpr h) + simp only [degreeOf_eq_sup, support_mul_X, this] + apply Finset.sup_le + intro x hx + simp only [Finset.sup_map, bot_eq_zero', add_pos_iff, zero_lt_one, or_true, Finset.le_sup_iff] + use x + simpa using mem_support_iff.mp hx + theorem degreeOf_C_mul_le (p : MvPolynomial σ R) (i : σ) (c : R) : (C c * p).degreeOf i ≤ p.degreeOf i := by unfold degreeOf @@ -484,6 +500,15 @@ theorem coeff_eq_zero_of_totalDegree_lt {f : MvPolynomial σ R} {d : σ →₀ exact lt_irrefl _ · exact lt_of_le_of_lt (Nat.zero_le _) h +theorem totalDegree_eq_zero_iff_eq_C {p : MvPolynomial σ R} : + p.totalDegree = 0 ↔ p = C (p.coeff 0) := by + constructor <;> intro h + · ext m; classical rw [coeff_C]; split_ifs with hm; · rw [← hm] + apply coeff_eq_zero_of_totalDegree_lt; rw [h] + exact Finset.sum_pos (fun i hi ↦ Nat.pos_of_ne_zero <| Finsupp.mem_support_iff.mp hi) + (Finsupp.support_nonempty_iff.mpr <| Ne.symm hm) + · rw [h, totalDegree_C] + theorem totalDegree_rename_le (f : σ → τ) (p : MvPolynomial σ R) : (rename f p).totalDegree ≤ p.totalDegree := Finset.sup_le fun b => by diff --git a/Mathlib/Algebra/MvPolynomial/Equiv.lean b/Mathlib/Algebra/MvPolynomial/Equiv.lean index ebcd5678aa4a4..5080eada19bc1 100644 --- a/Mathlib/Algebra/MvPolynomial/Equiv.lean +++ b/Mathlib/Algebra/MvPolynomial/Equiv.lean @@ -546,6 +546,11 @@ lemma finSuccEquiv_rename_finSuccEquiv (e : σ ≃ Fin n) (φ : MvPolynomial (Op end +@[simp] +theorem rename_polynomial_aeval_X {σ τ : Type*} (f : σ → τ) (i : σ) (p : R[X]) : + rename f (Polynomial.aeval (X i) p) = Polynomial.aeval (X (f i) : MvPolynomial τ R) p := by + rw [← aeval_algHom_apply, rename_X] + end Equiv end MvPolynomial diff --git a/Mathlib/Algebra/MvPolynomial/PDeriv.lean b/Mathlib/Algebra/MvPolynomial/PDeriv.lean index 9c6e2c3c43e7c..5cafce58bab3e 100644 --- a/Mathlib/Algebra/MvPolynomial/PDeriv.lean +++ b/Mathlib/Algebra/MvPolynomial/PDeriv.lean @@ -72,6 +72,13 @@ theorem pderiv_monomial {i : σ} : · rw [Finsupp.not_mem_support_iff] at hi; simp [hi] · simp +lemma X_mul_pderiv_monomial {i : σ} {m : σ →₀ ℕ} {r : R} : + X i * pderiv i (monomial m r) = m i • monomial m r := by + rw [pderiv_monomial, X, monomial_mul, smul_monomial] + by_cases h : m i = 0 + · simp_rw [h, Nat.cast_zero, mul_zero, zero_smul, monomial_zero] + rw [one_mul, mul_comm, nsmul_eq_mul, add_comm, sub_add_single_one_cancel h] + theorem pderiv_C {i : σ} : pderiv i (C a) = 0 := derivation_C _ _ diff --git a/Mathlib/Algebra/Order/Antidiag/Nat.lean b/Mathlib/Algebra/Order/Antidiag/Nat.lean index 40c8db2fe9e60..88a8cc741a284 100644 --- a/Mathlib/Algebra/Order/Antidiag/Nat.lean +++ b/Mathlib/Algebra/Order/Antidiag/Nat.lean @@ -11,11 +11,13 @@ import Mathlib.NumberTheory.ArithmeticFunction # Sets of tuples with a fixed product This file defines the finite set of `d`-tuples of natural numbers with a fixed product `n` as -`Nat.finMulAntidiagonal`. +`Nat.finMulAntidiag`. ## Main Results * There are `d^(ω n)` ways to write `n` as a product of `d` natural numbers, when `n` is squarefree -(`card_finMulAntidiagonal_of_squarefree`) +(`card_finMulAntidiag_of_squarefree`) +* There are `3^(ω n)` pairs of natural numbers whose `lcm` is `n`, when `n` is squarefree +(`card_pair_lcm_eq`) -/ open Finset @@ -239,4 +241,78 @@ theorem card_finMulAntidiag_of_squarefree {d n : ℕ} (hn : Squarefree n) : ArithmeticFunction.cardDistinctFactors_apply, ← List.card_toFinset, toFinset_factors, Finset.card_fin] +theorem finMulAntidiag_three {n : ℕ} : + ∀ a ∈ finMulAntidiag 3 n, a 0 * a 1 * a 2 = n := by + intro a ha + rw [← (mem_finMulAntidiag.mp ha).1, Fin.prod_univ_three a] + +namespace card_pair_lcm_eq + +/-! +The following private declarations are ingredients for the proof of `card_pair_lcm_eq`. +-/ + +@[reducible] +private def f {n : ℕ} : ∀ a ∈ finMulAntidiag 3 n, ℕ × ℕ := fun a _ => (a 0 * a 1, a 0 * a 2) + +private theorem f_img {n : ℕ} (hn : Squarefree n) (a : Fin 3 → ℕ) + (ha : a ∈ finMulAntidiag 3 n) : + f a ha ∈ Finset.filter (fun ⟨x, y⟩ => x.lcm y = n) (n.divisors ×ˢ n.divisors) := by + rw [mem_filter, Finset.mem_product, mem_divisors, mem_divisors] + refine ⟨⟨⟨?_, hn.ne_zero⟩, ⟨?_, hn.ne_zero⟩⟩, ?_⟩ <;> rw [f, ← finMulAntidiag_three a ha] + · apply dvd_mul_right + · use a 1; ring + dsimp only + rw [lcm_mul_left, Nat.Coprime.lcm_eq_mul] + · ring + refine coprime_of_squarefree_mul (hn.squarefree_of_dvd ?_) + use a 0; rw [← finMulAntidiag_three a ha]; ring + +private theorem f_inj {n : ℕ} (a : Fin 3 → ℕ) (ha : a ∈ finMulAntidiag 3 n) + (b : Fin 3 → ℕ) (hb : b ∈ finMulAntidiag 3 n) (hfab : f a ha = f b hb) : + a = b := by + obtain ⟨hfab1, hfab2⟩ := Prod.mk.inj hfab + have hprods : a 0 * a 1 * a 2 = a 0 * a 1 * b 2 := by + rw [finMulAntidiag_three a ha, hfab1, finMulAntidiag_three b hb] + have hab2 : a 2 = b 2 := by + rw [← mul_right_inj' <| mul_ne_zero (ne_zero_of_mem_finMulAntidiag ha 0) + (ne_zero_of_mem_finMulAntidiag ha 1)] + exact hprods + have hab0 : a 0 = b 0 := by + rw [hab2] at hfab2 + exact (mul_left_inj' <| ne_zero_of_mem_finMulAntidiag hb 2).mp hfab2; + have hab1 : a 1 = b 1 := by + rw [hab0] at hfab1 + exact (mul_right_inj' <| ne_zero_of_mem_finMulAntidiag hb 0).mp hfab1; + funext i; fin_cases i <;> assumption + +private theorem f_surj {n : ℕ} (hn : n ≠ 0) (b : ℕ × ℕ) + (hb : b ∈ Finset.filter (fun ⟨x, y⟩ => x.lcm y = n) (n.divisors ×ˢ n.divisors)) : + ∃ (a : Fin 3 → ℕ) (ha : a ∈ finMulAntidiag 3 n), f a ha = b := by + dsimp only at hb + let g := b.fst.gcd b.snd + let a := ![g, b.fst/g, b.snd/g] + have ha : a ∈ finMulAntidiag 3 n := by + rw [mem_finMulAntidiag] + rw [mem_filter, Finset.mem_product] at hb + refine ⟨?_, hn⟩ + · rw [Fin.prod_univ_three a] + simp only [a, Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons, + Matrix.cons_val_two, Matrix.tail_cons] + rw [Nat.mul_div_cancel_left' (Nat.gcd_dvd_left _ _), ← hb.2, lcm, + Nat.mul_div_assoc b.fst (Nat.gcd_dvd_right b.fst b.snd)] + use a; use ha + apply Prod.ext <;> simp only [Matrix.cons_val_zero, Matrix.cons_val_one, Matrix.head_cons] + <;> apply Nat.mul_div_cancel' + · apply Nat.gcd_dvd_left + · apply Nat.gcd_dvd_right + +end card_pair_lcm_eq + +open card_pair_lcm_eq in +theorem card_pair_lcm_eq {n : ℕ} (hn : Squarefree n) : + #{p ∈ (n.divisors ×ˢ n.divisors) | p.1.lcm p.2 = n} = 3 ^ ω n := by + rw [← card_finMulAntidiag_of_squarefree hn, eq_comm] + apply Finset.card_bij f (f_img hn) (f_inj) (f_surj hn.ne_zero) + end Nat diff --git a/Mathlib/Algebra/Order/Antidiag/Pi.lean b/Mathlib/Algebra/Order/Antidiag/Pi.lean index f2c11d7931ca5..aa2f6b9fb2e4a 100644 --- a/Mathlib/Algebra/Order/Antidiag/Pi.lean +++ b/Mathlib/Algebra/Order/Antidiag/Pi.lean @@ -223,7 +223,8 @@ lemma nsmul_piAntidiag [DecidableEq (ι → ℕ)] (s : Finset ι) (m : ℕ) {n : · rw [not_imp_comm.1 (hfsup _) hi] exact dvd_zero _ refine ⟨fun i ↦ f i / n, ?_⟩ - simpa [Nat.sum_div, Nat.div_ne_zero_iff_of_dvd, funext_iff, Nat.mul_div_cancel', ← Nat.sum_div, *] + simp [funext_iff, Nat.mul_div_cancel', ← Nat.sum_div, *] + aesop lemma map_nsmul_piAntidiag (s : Finset ι) (m : ℕ) {n : ℕ} (hn : n ≠ 0) : (piAntidiag s m).map diff --git a/Mathlib/Algebra/Order/Floor.lean b/Mathlib/Algebra/Order/Floor.lean index 0ec2dc284de96..286ee58459e4b 100644 --- a/Mathlib/Algebra/Order/Floor.lean +++ b/Mathlib/Algebra/Order/Floor.lean @@ -1044,7 +1044,6 @@ theorem fract_div_natCast_eq_div_natCast_mod {m n : ℕ} : fract ((m : k) / n) = norm_cast rw [← Nat.cast_add, Nat.mod_add_div m n] --- TODO Generalise this to allow `n : ℤ` using `Int.fmod` instead of `Int.mod`. theorem fract_div_intCast_eq_div_intCast_mod {m : ℤ} {n : ℕ} : fract ((m : k) / n) = ↑(m % n) / n := by rcases n.eq_zero_or_pos with (rfl | hn) diff --git a/Mathlib/Algebra/Order/Group/Opposite.lean b/Mathlib/Algebra/Order/Group/Opposite.lean index e145f616c4c11..bf68704269209 100644 --- a/Mathlib/Algebra/Order/Group/Opposite.lean +++ b/Mathlib/Algebra/Order/Group/Opposite.lean @@ -51,10 +51,10 @@ variable [OrderedAddCommMonoid α] instance : OrderedAddCommMonoid αᵐᵒᵖ where add_le_add_left a b hab c := add_le_add_left (by simpa) c.unop -@[simp] lemma unop_nonneg {a : αᵐᵒᵖ} : unop a ≤ 0 ↔ a ≤ 0 := .rfl -@[simp] lemma unop_nonpos {a : αᵐᵒᵖ} : 0 ≤ unop a ↔ 0 ≤ a := .rfl -@[simp] lemma op_nonneg {a : α} : op a ≤ 0 ↔ a ≤ 0 := .rfl -@[simp] lemma op_nonpos {a : α} : 0 ≤ op a ↔ 0 ≤ a := .rfl +@[simp] lemma unop_nonpos {a : αᵐᵒᵖ} : unop a ≤ 0 ↔ a ≤ 0 := .rfl +@[simp] lemma unop_nonneg {a : αᵐᵒᵖ} : 0 ≤ unop a ↔ 0 ≤ a := .rfl +@[simp] lemma op_nonpos {a : α} : op a ≤ 0 ↔ a ≤ 0 := .rfl +@[simp] lemma op_nonneg {a : α} : 0 ≤ op a ↔ 0 ≤ a := .rfl end OrderedAddCommMonoid diff --git a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean index 294f6be7c92df..90e52eaed78c7 100644 --- a/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean +++ b/Mathlib/Algebra/Order/Group/Pointwise/Bounds.lean @@ -26,7 +26,7 @@ variable [Mul M] [Preorder M] [MulLeftMono M] @[to_additive] lemma mul_mem_upperBounds_mul (ha : a ∈ upperBounds s) (hb : b ∈ upperBounds t) : - a * b ∈ upperBounds (s * t) := forall_image2_iff.2 fun _ hx _ hy => mul_le_mul' (ha hx) (hb hy) + a * b ∈ upperBounds (s * t) := forall_mem_image2.2 fun _ hx _ hy => mul_le_mul' (ha hx) (hb hy) @[to_additive] lemma subset_upperBounds_mul (s t : Set M) : upperBounds s * upperBounds t ⊆ upperBounds (s * t) := diff --git a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean index 03c9d7579e5f1..122d83453934b 100644 --- a/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Group/Unbundled/Basic.lean @@ -537,6 +537,8 @@ section LE variable [LE α] [MulLeftMono α] {a b c d : α} +/-- See also `div_le_div_iff` for a version that works for `LinearOrderedSemifield` with +additional assumptions. -/ @[to_additive sub_le_sub_iff] theorem div_le_div_iff' : a / b ≤ c / d ↔ a * d ≤ c * b := by simpa only [div_eq_mul_inv] using mul_inv_le_mul_inv_iff' diff --git a/Mathlib/Algebra/Order/Group/Unbundled/Int.lean b/Mathlib/Algebra/Order/Group/Unbundled/Int.lean index 96c6eed502379..2fad62292ee5a 100644 --- a/Mathlib/Algebra/Order/Group/Unbundled/Int.lean +++ b/Mathlib/Algebra/Order/Group/Unbundled/Int.lean @@ -46,6 +46,9 @@ theorem natAbs_abs (a : ℤ) : natAbs |a| = natAbs a := by rw [abs_eq_natAbs]; r theorem sign_mul_abs (a : ℤ) : sign a * |a| = a := by rw [abs_eq_natAbs, sign_mul_natAbs a] +theorem sign_mul_self_eq_abs (a : ℤ) : sign a * a = |a| := by + rw [abs_eq_natAbs, sign_mul_self_eq_natAbs] + lemma natAbs_le_self_sq (a : ℤ) : (Int.natAbs a : ℤ) ≤ a ^ 2 := by rw [← Int.natAbs_sq a, sq] norm_cast @@ -129,6 +132,10 @@ protected theorem sign_eq_ediv_abs (a : ℤ) : sign a = a / |a| := if az : a = 0 then by simp [az] else (Int.ediv_eq_of_eq_mul_left (mt abs_eq_zero.1 az) (sign_mul_abs _).symm).symm +protected theorem sign_eq_abs_ediv (a : ℤ) : sign a = |a| / a := + if az : a = 0 then by simp [az] + else (Int.ediv_eq_of_eq_mul_left az (sign_mul_self_eq_abs _).symm).symm + end Int section Group diff --git a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean index 3a29eb4977c1c..01454ee338502 100644 --- a/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean +++ b/Mathlib/Algebra/Order/GroupWithZero/Unbundled.lean @@ -89,13 +89,11 @@ open Function variable {M₀ G₀ : Type*} (α : Type*) -set_option quotPrecheck false in -/-- Local notation for the nonnegative elements of a type `α`. TODO: actually make local. -/ -notation "α≥0" => { x : α // 0 ≤ x } +/-- Local notation for the nonnegative elements of a type `α`. -/ +local notation3 "α≥0" => { x : α // 0 ≤ x } -set_option quotPrecheck false in -/-- Local notation for the positive elements of a type `α`. TODO: actually make local. -/ -notation "α>0" => { x : α // 0 < x } +/-- Local notation for the positive elements of a type `α`. -/ +local notation3 "α>0" => { x : α // 0 < x } section Abbreviations @@ -1109,7 +1107,7 @@ lemma strictMonoOn_mul_self [PosMulStrictMono M₀] [MulPosMono M₀] : -- See Note [decidable namespace] protected lemma Decidable.mul_lt_mul'' [PosMulMono M₀] [PosMulStrictMono M₀] [MulPosStrictMono M₀] - [@DecidableRel M₀ (· ≤ ·)] (h1 : a < c) (h2 : b < d) + [DecidableRel (α := M₀) (· ≤ ·)] (h1 : a < c) (h2 : b < d) (h3 : 0 ≤ a) (h4 : 0 ≤ b) : a * b < c * d := h4.lt_or_eq_dec.elim (fun b0 ↦ mul_lt_mul h1 h2.le b0 <| h3.trans h1.le) fun b0 ↦ by rw [← b0, mul_zero]; exact mul_pos (h3.trans_lt h1) (h4.trans_lt h2) diff --git a/Mathlib/Algebra/Order/Hom/Monoid.lean b/Mathlib/Algebra/Order/Hom/Monoid.lean index b40dacaccb13e..d7ee5915f5f32 100644 --- a/Mathlib/Algebra/Order/Hom/Monoid.lean +++ b/Mathlib/Algebra/Order/Hom/Monoid.lean @@ -90,8 +90,8 @@ structure. When possible, instead of parametrizing results over `(f : α ≃+o β)`, you should parametrize over `(F : Type*) [FunLike F M N] [AddEquivClass F M N] [OrderIsoClass F M N] (f : F)`. -/ -structure OrderAddMonoidIso (α β : Type*) [Preorder α] [Preorder β] [AddZeroClass α] - [AddZeroClass β] extends α ≃+ β where +structure OrderAddMonoidIso (α β : Type*) [Preorder α] [Preorder β] [Add α] [Add β] + extends α ≃+ β where /-- An `OrderAddMonoidIso` respects `≤`. -/ map_le_map_iff' {a b : α} : toFun a ≤ toFun b ↔ a ≤ b @@ -146,8 +146,8 @@ When possible, instead of parametrizing results over `(f : α ≃*o β)`, you should parametrize over `(F : Type*) [FunLike F M N] [MulEquivClass F M N] [OrderIsoClass F M N] (f : F)`. -/ @[to_additive] -structure OrderMonoidIso (α β : Type*) [Preorder α] [Preorder β] [MulOneClass α] - [MulOneClass β] extends α ≃* β where +structure OrderMonoidIso (α β : Type*) [Preorder α] [Preorder β] [Mul α] [Mul β] + extends α ≃* β where /-- An `OrderMonoidIso` respects `≤`. -/ map_le_map_iff' {a b : α} : toFun a ≤ toFun b ↔ a ≤ b @@ -513,8 +513,8 @@ namespace OrderMonoidIso section Preorder -variable [Preorder α] [Preorder β] [Preorder γ] [Preorder δ] [MulOneClass α] [MulOneClass β] - [MulOneClass γ] [MulOneClass δ] {f g : α ≃*o β} +variable [Preorder α] [Preorder β] [Preorder γ] [Preorder δ] [Mul α] [Mul β] + [Mul γ] [Mul δ] {f g : α ≃*o β} @[to_additive] instance : EquivLike (α ≃*o β) α β where diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean index 0e9d89e4f69f8..a6577a705c6e3 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/Basic.lean @@ -293,9 +293,17 @@ lemma mul_max [CovariantClass α α (· * ·) (· ≤ ·)] (a b c : α) : a * max b c = max (a * b) (a * c) := mul_left_mono.map_max @[to_additive] -lemma max_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] : +lemma max_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : max a b * c = max (a * c) (b * c) := mul_right_mono.map_max +@[to_additive] +lemma mul_min [CovariantClass α α (· * ·) (· ≤ ·)] (a b c : α) : + a * min b c = min (a * b) (a * c) := mul_left_mono.map_min + +@[to_additive] +lemma min_mul [CovariantClass α α (swap (· * ·)) (· ≤ ·)] (a b c : α) : + min a b * c = min (a * c) (b * c) := mul_right_mono.map_min + @[to_additive] lemma min_lt_max_of_mul_lt_mul [MulLeftMono α] [MulRightMono α] (h : a * b < c * d) : min a b < max c d := by diff --git a/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean index 761ae23ae5a20..483877e4fee6e 100644 --- a/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean +++ b/Mathlib/Algebra/Order/Monoid/Unbundled/TypeTags.lean @@ -86,6 +86,11 @@ theorem toMul_le {a b : Additive α} : a.toMul ≤ b.toMul ↔ a ≤ b := theorem toMul_lt {a b : Additive α} : a.toMul < b.toMul ↔ a < b := Iff.rfl +@[gcongr] alias ⟨_, toMul_mono⟩ := toMul_le +@[gcongr] alias ⟨_, ofMul_mono⟩ := ofMul_le +@[gcongr] alias ⟨_, toMul_strictMono⟩ := toMul_lt +@[gcongr] alias ⟨_, foMul_strictMono⟩ := ofMul_lt + end Additive namespace Multiplicative @@ -108,4 +113,9 @@ theorem toAdd_le {a b : Multiplicative α} : a.toAdd ≤ b.toAdd ↔ a ≤ b := theorem toAdd_lt {a b : Multiplicative α} : a.toAdd < b.toAdd ↔ a < b := Iff.rfl +@[gcongr] alias ⟨_, toAdd_mono⟩ := toAdd_le +@[gcongr] alias ⟨_, ofAdd_mono⟩ := ofAdd_le +@[gcongr] alias ⟨_, toAdd_strictMono⟩ := toAdd_lt +@[gcongr] alias ⟨_, ofAdd_strictMono⟩ := ofAdd_lt + end Multiplicative diff --git a/Mathlib/Algebra/Order/Quantale.lean b/Mathlib/Algebra/Order/Quantale.lean index 96bfa1624aa35..13108eac3152d 100644 --- a/Mathlib/Algebra/Order/Quantale.lean +++ b/Mathlib/Algebra/Order/Quantale.lean @@ -176,4 +176,21 @@ theorem rightMulResiduation_le_iff_mul_le : x ≤ y ⇨ᵣ z ↔ y * x ≤ z whe iSup_le_iff, implies_true] mpr h1 := le_sSup h1 +section Zero + +variable {α : Type*} [Semigroup α] [CompleteLattice α] [IsQuantale α] +variable {x : α} + +@[to_additive (attr := simp)] +theorem bot_mul : ⊥ * x = ⊥ := by + rw [← sSup_empty, sSup_mul_distrib] + simp only [Set.mem_empty_iff_false, not_false_eq_true, iSup_neg, iSup_bot, sSup_empty] + +@[to_additive (attr := simp)] +theorem mul_bot : x * ⊥ = ⊥ := by + rw [← sSup_empty, mul_sSup_distrib] + simp only [Set.mem_empty_iff_false, not_false_eq_true, iSup_neg, iSup_bot, sSup_empty] + +end Zero + end IsQuantale diff --git a/Mathlib/Algebra/Order/Ring/Defs.lean b/Mathlib/Algebra/Order/Ring/Defs.lean index d9128b14a9a37..a8f2ee51df52a 100644 --- a/Mathlib/Algebra/Order/Ring/Defs.lean +++ b/Mathlib/Algebra/Order/Ring/Defs.lean @@ -265,7 +265,8 @@ instance (priority := 200) StrictOrderedSemiring.toMulPosStrictMono : MulPosStri -- See note [reducible non-instances] /-- A choice-free version of `StrictOrderedSemiring.toOrderedSemiring` to avoid using choice in basic `Nat` lemmas. -/ -abbrev StrictOrderedSemiring.toOrderedSemiring' [@DecidableRel α (· ≤ ·)] : OrderedSemiring α := +abbrev StrictOrderedSemiring.toOrderedSemiring' [DecidableRel (α := α) (· ≤ ·)] : + OrderedSemiring α := { ‹StrictOrderedSemiring α› with mul_le_mul_of_nonneg_left := fun a b c hab hc => by obtain rfl | hab := Decidable.eq_or_lt_of_le hab @@ -308,7 +309,7 @@ variable [StrictOrderedCommSemiring α] -- See note [reducible non-instances] /-- A choice-free version of `StrictOrderedCommSemiring.toOrderedCommSemiring'` to avoid using choice in basic `Nat` lemmas. -/ -abbrev StrictOrderedCommSemiring.toOrderedCommSemiring' [@DecidableRel α (· ≤ ·)] : +abbrev StrictOrderedCommSemiring.toOrderedCommSemiring' [DecidableRel (α := α) (· ≤ ·)] : OrderedCommSemiring α := { ‹StrictOrderedCommSemiring α›, StrictOrderedSemiring.toOrderedSemiring' with } @@ -334,7 +335,7 @@ instance (priority := 100) StrictOrderedRing.toStrictOrderedSemiring : StrictOrd -- See note [reducible non-instances] /-- A choice-free version of `StrictOrderedRing.toOrderedRing` to avoid using choice in basic `Int` lemmas. -/ -abbrev StrictOrderedRing.toOrderedRing' [@DecidableRel α (· ≤ ·)] : OrderedRing α := +abbrev 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 @@ -357,7 +358,8 @@ variable [StrictOrderedCommRing α] -- See note [reducible non-instances] /-- A choice-free version of `StrictOrderedCommRing.toOrderedCommRing` to avoid using choice in basic `Int` lemmas. -/ -abbrev StrictOrderedCommRing.toOrderedCommRing' [@DecidableRel α (· ≤ ·)] : OrderedCommRing α := +abbrev StrictOrderedCommRing.toOrderedCommRing' [DecidableRel (α := α) (· ≤ ·)] : + OrderedCommRing α := { ‹StrictOrderedCommRing α›, StrictOrderedRing.toOrderedRing' with } -- See note [lower instance priority] diff --git a/Mathlib/Algebra/Order/Ring/InjSurj.lean b/Mathlib/Algebra/Order/Ring/InjSurj.lean index f8f659b32ebbc..1942166c409a7 100644 --- a/Mathlib/Algebra/Order/Ring/InjSurj.lean +++ b/Mathlib/Algebra/Order/Ring/InjSurj.lean @@ -74,7 +74,7 @@ protected abbrev strictOrderedSemiring [StrictOrderedSemiring α] (zero : f 0 = (natCast : ∀ n : ℕ, f n = n) : StrictOrderedSemiring β where toSemiring := hf.semiring f zero one add mul nsmul npow natCast __ := hf.orderedCancelAddCommMonoid f zero add (swap nsmul) - __ := pullback_nonzero f zero one + __ := domain_nontrivial f zero one __ := hf.orderedSemiring f zero one add mul nsmul npow natCast mul_lt_mul_of_pos_left a b c h hc := show f (c * a) < f (c * b) by simpa only [mul, zero] using mul_lt_mul_of_pos_left ‹f a < f b› (by rwa [← zero]) diff --git a/Mathlib/Algebra/Order/Sub/WithTop.lean b/Mathlib/Algebra/Order/Sub/WithTop.lean index f6b0e29c1f838..5b2d1da2ff61f 100644 --- a/Mathlib/Algebra/Order/Sub/WithTop.lean +++ b/Mathlib/Algebra/Order/Sub/WithTop.lean @@ -76,6 +76,7 @@ instance : OrderedSub (WithTop α) := by · simp cases z · simp - norm_cast; exact tsub_le_iff_right + norm_cast + exact tsub_le_iff_right end WithTop diff --git a/Mathlib/Algebra/Order/SuccPred.lean b/Mathlib/Algebra/Order/SuccPred.lean index 185ea8250d6f9..faf2e279f4aa8 100644 --- a/Mathlib/Algebra/Order/SuccPred.lean +++ b/Mathlib/Algebra/Order/SuccPred.lean @@ -6,7 +6,7 @@ Authors: Violeta Hernández Palacios, Yaël Dillies import Mathlib.Algebra.Group.Basic import Mathlib.Algebra.Order.ZeroLEOne import Mathlib.Data.Int.Cast.Defs -import Mathlib.Order.SuccPred.Archimedean +import Mathlib.Order.SuccPred.Limit /-! # Interaction between successors and arithmetic @@ -138,6 +138,46 @@ theorem covBy_iff_sub_one_eq [Sub α] [One α] [PredSubOrder α] [NoMinOrder α] rw [← pred_eq_sub_one] exact pred_eq_iff_covBy.symm +theorem IsSuccPrelimit.add_one_lt [Add α] [One α] [SuccAddOrder α] + (hx : IsSuccPrelimit x) (hy : y < x) : y + 1 < x := by + rw [← succ_eq_add_one] + exact hx.succ_lt hy + +theorem IsPredPrelimit.lt_sub_one [Sub α] [One α] [PredSubOrder α] + (hx : IsPredPrelimit x) (hy : x < y) : x < y - 1 := by + rw [← pred_eq_sub_one] + exact hx.lt_pred hy + +theorem IsSuccLimit.add_one_lt [Add α] [One α] [SuccAddOrder α] + (hx : IsSuccLimit x) (hy : y < x) : y + 1 < x := + hx.isSuccPrelimit.add_one_lt hy + +theorem IsPredLimit.lt_sub_one [Sub α] [One α] [PredSubOrder α] + (hx : IsPredLimit x) (hy : x < y) : x < y - 1 := + hx.isPredPrelimit.lt_sub_one hy + +theorem IsSuccPrelimit.add_natCast_lt [AddMonoidWithOne α] [SuccAddOrder α] + (hx : IsSuccPrelimit x) (hy : y < x) : ∀ n : ℕ, y + n < x + | 0 => by simpa + | n + 1 => by + rw [Nat.cast_add_one, ← add_assoc] + exact hx.add_one_lt (hx.add_natCast_lt hy n) + +theorem IsPredPrelimit.lt_sub_natCast [AddCommGroupWithOne α] [PredSubOrder α] + (hx : IsPredPrelimit x) (hy : x < y) : ∀ n : ℕ, x < y - n + | 0 => by simpa + | n + 1 => by + rw [Nat.cast_add_one, ← sub_sub] + exact hx.lt_sub_one (hx.lt_sub_natCast hy n) + +theorem IsSuccLimit.add_natCast_lt [AddMonoidWithOne α] [SuccAddOrder α] + (hx : IsSuccLimit x) (hy : y < x) : ∀ n : ℕ, y + n < x := + hx.isSuccPrelimit.add_natCast_lt hy + +theorem IsPredLimit.lt_sub_natCast [AddCommGroupWithOne α] [PredSubOrder α] + (hx : IsPredLimit x) (hy : x < y) : ∀ n : ℕ, x < y - n := + hx.isPredPrelimit.lt_sub_natCast hy + end PartialOrder section LinearOrder diff --git a/Mathlib/Algebra/Pointwise/Stabilizer.lean b/Mathlib/Algebra/Pointwise/Stabilizer.lean index 0596f27478672..2a1b5ea298aad 100644 --- a/Mathlib/Algebra/Pointwise/Stabilizer.lean +++ b/Mathlib/Algebra/Pointwise/Stabilizer.lean @@ -16,11 +16,13 @@ open Function MulOpposite Set open scoped Pointwise namespace MulAction -variable {G H α : Type*} [Group G] [Group H] [MulAction G α] {a : G} +variable {G H α : Type*} /-! ### Stabilizer of a set -/ section Set +section Group +variable [Group G] [Group H] [MulAction G α] {a : G} {s t : Set α} @[to_additive (attr := simp)] lemma stabilizer_empty : stabilizer G (∅ : Set α) = ⊤ := @@ -57,8 +59,77 @@ lemma stabilizer_mul_self (s : Set G) : (stabilizer G s : Set G) * s = s := by rw [← mem_stabilizer_iff.1 ha] exact smul_mem_smul_set hb +@[to_additive] +lemma stabilizer_inf_stabilizer_le_stabilizer_apply₂ {f : Set α → Set α → Set α} + (hf : ∀ a : G, a • f s t = f (a • s) (a • t)) : + stabilizer G s ⊓ stabilizer G t ≤ stabilizer G (f s t) := by aesop (add simp [SetLike.le_def]) + +@[to_additive] +lemma stabilizer_inf_stabilizer_le_stabilizer_union : + stabilizer G s ⊓ stabilizer G t ≤ stabilizer G (s ∪ t) := + stabilizer_inf_stabilizer_le_stabilizer_apply₂ fun _ ↦ smul_set_union + +@[to_additive] +lemma stabilizer_inf_stabilizer_le_stabilizer_inter : + stabilizer G s ⊓ stabilizer G t ≤ stabilizer G (s ∩ t) := + stabilizer_inf_stabilizer_le_stabilizer_apply₂ fun _ ↦ smul_set_inter + +@[to_additive] +lemma stabilizer_inf_stabilizer_le_stabilizer_sdiff : + stabilizer G s ⊓ stabilizer G t ≤ stabilizer G (s \ t) := + stabilizer_inf_stabilizer_le_stabilizer_apply₂ fun _ ↦ smul_set_sdiff + +@[to_additive] +lemma stabilizer_union_eq_left (hdisj : Disjoint s t) (hstab : stabilizer G s ≤ stabilizer G t) + (hstab_union : stabilizer G (s ∪ t) ≤ stabilizer G t) : + stabilizer G (s ∪ t) = stabilizer G s := by + refine le_antisymm ?_ ?_ + · calc + stabilizer G (s ∪ t) + ≤ stabilizer G (s ∪ t) ⊓ stabilizer G t := by simpa + _ ≤ stabilizer G ((s ∪ t) \ t) := stabilizer_inf_stabilizer_le_stabilizer_sdiff + _ = stabilizer G s := by rw [union_diff_cancel_right]; simpa [← disjoint_iff_inter_eq_empty] + · calc + stabilizer G s + ≤ stabilizer G s ⊓ stabilizer G t := by simpa + _ ≤ stabilizer G (s ∪ t) := stabilizer_inf_stabilizer_le_stabilizer_union + +@[to_additive] +lemma stabilizer_union_eq_right (hdisj : Disjoint s t) (hstab : stabilizer G t ≤ stabilizer G s) + (hstab_union : stabilizer G (s ∪ t) ≤ stabilizer G s) : + stabilizer G (s ∪ t) = stabilizer G t := by + rw [union_comm, stabilizer_union_eq_left hdisj.symm hstab (union_comm .. ▸ hstab_union)] + +variable {s : Set G} + +open scoped RightActions in +@[to_additive] +lemma op_smul_set_stabilizer_subset (ha : a ∈ s) : (stabilizer G s : Set G) <• a ⊆ s := + smul_set_subset_iff.2 fun b hb ↦ by rw [← hb]; exact smul_mem_smul_set ha + +@[to_additive] +lemma stabilizer_subset_div_right (ha : a ∈ s) : ↑(stabilizer G s) ⊆ s / {a} := fun b hb ↦ + ⟨_, by rwa [← smul_eq_mul, mem_stabilizer_set.1 hb], _, mem_singleton _, mul_div_cancel_right _ _⟩ + +@[to_additive] +lemma stabilizer_finite (hs₀ : s.Nonempty) (hs : s.Finite) : (stabilizer G s : Set G).Finite := by + obtain ⟨a, ha⟩ := hs₀ + exact (hs.div <| finite_singleton _).subset <| stabilizer_subset_div_right ha + +end Group + +section CommGroup +variable [CommGroup G] {s t : Set G} {a : G} + +@[to_additive] +lemma smul_set_stabilizer_subset (ha : a ∈ s) : a • (stabilizer G s : Set G) ⊆ s := by + simpa using op_smul_set_stabilizer_subset ha + +end CommGroup end Set +variable [Group G] [Group H] [MulAction G α] {a : G} + /-! ### Stabilizer of a subgroup -/ section Subgroup @@ -92,7 +163,7 @@ end Subgroup section Finset variable [DecidableEq α] -@[to_additive (attr := simp)] +@[to_additive (attr := simp, norm_cast)] lemma stabilizer_coe_finset (s : Finset α) : stabilizer G (s : Set α) = stabilizer G s := by ext; simp [← Finset.coe_inj] @@ -132,6 +203,8 @@ end Finset /-! ### Stabilizer of a finite set -/ +variable {s : Set α} + @[to_additive] lemma mem_stabilizer_set_iff_subset_smul_set {s : Set α} (hs : s.Finite) : a ∈ stabilizer G s ↔ s ⊆ a • s := by @@ -148,6 +221,12 @@ lemma mem_stabilizer_set_iff_smul_set_subset {s : Set α} (hs : s.Finite) : rw [stabilizer_coe_finset, mem_stabilizer_finset_iff_smul_finset_subset, ← Finset.coe_smul_finset, Finset.coe_subset] +@[deprecated (since := "2024-11-25")] +alias mem_stabilizer_of_finite_iff_smul_le := mem_stabilizer_set_iff_subset_smul_set + +@[deprecated (since := "2024-11-25")] +alias mem_stabilizer_of_finite_iff_le_smul := mem_stabilizer_set_iff_smul_set_subset + @[to_additive] lemma mem_stabilizer_set' {s : Set α} (hs : s.Finite) : a ∈ stabilizer G s ↔ ∀ ⦃b⦄, b ∈ s → a • b ∈ s := by diff --git a/Mathlib/Algebra/Polynomial/AlgebraMap.lean b/Mathlib/Algebra/Polynomial/AlgebraMap.lean index 3431db816584a..b58d9b56eb9b1 100644 --- a/Mathlib/Algebra/Polynomial/AlgebraMap.lean +++ b/Mathlib/Algebra/Polynomial/AlgebraMap.lean @@ -4,11 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker -/ import Mathlib.Algebra.Algebra.Pi +import Mathlib.Algebra.Algebra.Subalgebra.Basic +import Mathlib.Algebra.Algebra.Tower import Mathlib.Algebra.MonoidAlgebra.Basic import Mathlib.Algebra.Polynomial.Eval.Algebra import Mathlib.Algebra.Polynomial.Eval.Degree import Mathlib.Algebra.Polynomial.Monomial -import Mathlib.RingTheory.Adjoin.Basic /-! # Theory of univariate polynomials @@ -17,6 +18,7 @@ We show that `A[X]` is an R-algebra when `A` is an R-algebra. We promote `eval₂` to an algebra hom in `aeval`. -/ +assert_not_exists Ideal noncomputable section @@ -230,13 +232,6 @@ This is a stronger variant of the linear map `Polynomial.leval`. -/ def aeval : R[X] →ₐ[R] A := eval₂AlgHom' (Algebra.ofId _ _) x (Algebra.commutes · _) -@[simp] -theorem adjoin_X : Algebra.adjoin R ({X} : Set R[X]) = ⊤ := by - refine top_unique fun p _hp => ?_ - set S := Algebra.adjoin R ({X} : Set R[X]) - rw [← sum_monomial_eq p]; simp only [← smul_X_eq_monomial, Sum] - exact S.sum_mem fun n _hn => S.smul_mem (S.pow_mem (Algebra.subset_adjoin rfl) _) _ - @[ext 1200] theorem algHom_ext {f g : R[X] →ₐ[R] B} (hX : f X = g X) : f = g := @@ -415,31 +410,6 @@ theorem aeval_eq_zero_of_dvd_aeval_eq_zero [CommSemiring S] [CommSemiring T] [Al rw [aeval_def, ← eval_map] at h₂ ⊢ exact eval_eq_zero_of_dvd_of_eval_eq_zero (Polynomial.map_dvd (algebraMap S T) h₁) h₂ -variable (R) - -theorem _root_.Algebra.adjoin_singleton_eq_range_aeval (x : A) : - Algebra.adjoin R {x} = (Polynomial.aeval x).range := by - rw [← Algebra.map_top, ← adjoin_X, AlgHom.map_adjoin, Set.image_singleton, aeval_X] - -@[simp] -theorem aeval_mem_adjoin_singleton : - aeval x p ∈ Algebra.adjoin R {x} := by - simpa only [Algebra.adjoin_singleton_eq_range_aeval] using Set.mem_range_self p - -instance instCommSemiringAdjoinSingleton : - CommSemiring <| Algebra.adjoin R {x} := - { mul_comm := fun ⟨p, hp⟩ ⟨q, hq⟩ ↦ by - obtain ⟨p', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hp - obtain ⟨q', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hq - simp only [AlgHom.toRingHom_eq_coe, RingHom.coe_coe, MulMemClass.mk_mul_mk, ← map_mul, - mul_comm p' q'] } - -instance instCommRingAdjoinSingleton {R A : Type*} [CommRing R] [Ring A] [Algebra R A] (x : A) : - CommRing <| Algebra.adjoin R {x} := - { mul_comm := mul_comm } - -variable {R} - section Semiring variable [Semiring S] {f : R →+* S} diff --git a/Mathlib/Algebra/Polynomial/Basic.lean b/Mathlib/Algebra/Polynomial/Basic.lean index 72765a3a6e65a..93d9b0870d987 100644 --- a/Mathlib/Algebra/Polynomial/Basic.lean +++ b/Mathlib/Algebra/Polynomial/Basic.lean @@ -135,6 +135,11 @@ instance smulZeroClass {S : Type*} [SMulZeroClass S R] : SMulZeroClass S R[X] wh smul r p := ⟨r • p.toFinsupp⟩ smul_zero a := congr_arg ofFinsupp (smul_zero a) +instance {S : Type*} [Zero S] [SMulZeroClass S R] [NoZeroSMulDivisors S R] : + NoZeroSMulDivisors S R[X] where + eq_zero_or_eq_zero_of_smul_eq_zero eq := + (eq_zero_or_eq_zero_of_smul_eq_zero <| congr_arg toFinsupp eq).imp id (congr_arg ofFinsupp) + -- to avoid a bug in the `ring` tactic instance (priority := 1) pow : Pow R[X] ℕ where pow p n := npowRec n p @@ -759,6 +764,12 @@ theorem support_monomial' (n) (a : R) : (monomial n a).support ⊆ singleton n : rw [← ofFinsupp_single, support] exact Finsupp.support_single_subset +theorem support_C {a : R} (h : a ≠ 0) : (C a).support = singleton 0 := + support_monomial 0 h + +theorem support_C_subset (a : R) : (C a).support ⊆ singleton 0 := + support_monomial' 0 a + theorem support_C_mul_X {c : R} (h : c ≠ 0) : Polynomial.support (C c * X) = singleton 1 := by rw [C_mul_X_eq_monomial, support_monomial 1 h] diff --git a/Mathlib/Algebra/Polynomial/Coeff.lean b/Mathlib/Algebra/Polynomial/Coeff.lean index 383ce0d93d741..1997d5ce972f0 100644 --- a/Mathlib/Algebra/Polynomial/Coeff.lean +++ b/Mathlib/Algebra/Polynomial/Coeff.lean @@ -101,6 +101,7 @@ lemma coeff_list_sum_map {ι : Type*} (l : List ι) (f : ι → R[X]) (n : ℕ) (l.map f).sum.coeff n = (l.map (fun a => (f a).coeff n)).sum := by simp_rw [coeff_list_sum, List.map_map, Function.comp_def, lcoeff_apply] +@[simp] theorem coeff_sum [Semiring S] (n : ℕ) (f : ℕ → R → S[X]) : coeff (p.sum f) n = p.sum fun a b => coeff (f a b) n := by rcases p with ⟨⟩ diff --git a/Mathlib/Algebra/Polynomial/Degree/Domain.lean b/Mathlib/Algebra/Polynomial/Degree/Domain.lean index cad96a6912720..04519630e17d6 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Domain.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Domain.lean @@ -40,6 +40,15 @@ lemma natDegree_mul (hp : p ≠ 0) (hq : q ≠ 0) : (p*q).natDegree = p.natDegre rw [← Nat.cast_inj (R := WithBot ℕ), ← degree_eq_natDegree (mul_ne_zero hp hq), Nat.cast_add, ← degree_eq_natDegree hp, ← degree_eq_natDegree hq, degree_mul] +variable (p) in +lemma natDegree_smul (ha : a ≠ 0) : (a • p).natDegree = p.natDegree := by + by_cases hp : p = 0 + · simp only [hp, smul_zero] + · apply natDegree_eq_of_le_of_coeff_ne_zero + · exact (natDegree_smul_le _ _).trans (le_refl _) + · simpa only [coeff_smul, coeff_natDegree, smul_eq_mul, ne_eq, mul_eq_zero, + leadingCoeff_eq_zero, not_or] using ⟨ha, hp⟩ + @[simp] lemma natDegree_pow (p : R[X]) (n : ℕ) : natDegree (p ^ n) = n * natDegree p := by classical diff --git a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean index 22a6b53a366a2..6f001cb5e20e7 100644 --- a/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean +++ b/Mathlib/Algebra/Polynomial/Degree/Lemmas.lean @@ -271,7 +271,7 @@ theorem degree_map_eq_iff {f : R →+* S} {p : Polynomial R} : theorem natDegree_map_eq_iff {f : R →+* S} {p : Polynomial R} : natDegree (map f p) = natDegree p ↔ f (p.leadingCoeff) ≠ 0 ∨ natDegree p = 0 := by rcases eq_or_ne (natDegree p) 0 with h|h - · simp_rw [h, ne_eq, or_true, iff_true, ← Nat.le_zero, ← h, natDegree_map_le f p] + · simp_rw [h, ne_eq, or_true, iff_true, ← Nat.le_zero, ← h, natDegree_map_le] have h2 : p ≠ 0 := by rintro rfl; simp at h have h3 : degree p ≠ (0 : ℕ) := degree_ne_of_natDegree_ne h simp_rw [h, or_false, natDegree, WithBot.unbot'_eq_unbot'_iff, degree_map_eq_iff] @@ -369,20 +369,16 @@ theorem leadingCoeff_comp (hq : natDegree q ≠ 0) : end NoZeroDivisors -section CommRing -variable [CommRing R] {p q : R[X]} - -@[simp] lemma comp_neg_X_leadingCoeff_eq (p : R[X]) : +@[simp] lemma comp_neg_X_leadingCoeff_eq [Ring R] (p : R[X]) : (p.comp (-X)).leadingCoeff = (-1) ^ p.natDegree * p.leadingCoeff := by nontriviality R by_cases h : p = 0 · simp [h] rw [Polynomial.leadingCoeff, natDegree_comp_eq_of_mul_ne_zero, coeff_comp_degree_mul_degree] <;> - simp [mul_comm, h] - -variable [IsDomain R] + simp [((Commute.neg_one_left _).pow_left _).eq, h] -lemma comp_eq_zero_iff : p.comp q = 0 ↔ p = 0 ∨ p.eval (q.coeff 0) = 0 ∧ q = C (q.coeff 0) := by +lemma comp_eq_zero_iff [Semiring R] [NoZeroDivisors R] {p q : R[X]} : + p.comp q = 0 ↔ p = 0 ∨ p.eval (q.coeff 0) = 0 ∧ q = C (q.coeff 0) := by refine ⟨fun h ↦ ?_, Or.rec (fun h ↦ by simp [h]) fun h ↦ by rw [h.2, comp_C, h.1, C_0]⟩ have key : p.natDegree = 0 ∨ q.natDegree = 0 := by rw [← mul_eq_zero, ← natDegree_comp, h, natDegree_zero] @@ -392,8 +388,6 @@ lemma comp_eq_zero_iff : p.comp q = 0 ↔ p = 0 ∨ p.eval (q.coeff 0) = 0 ∧ q · rw [key, comp_C, C_eq_zero] at h exact Or.inr ⟨h, key⟩ -end CommRing - section DivisionRing variable {K : Type*} [DivisionRing K] diff --git a/Mathlib/Algebra/Polynomial/Derivation.lean b/Mathlib/Algebra/Polynomial/Derivation.lean index 5a14afb6cc51f..b069960426f67 100644 --- a/Mathlib/Algebra/Polynomial/Derivation.lean +++ b/Mathlib/Algebra/Polynomial/Derivation.lean @@ -6,6 +6,7 @@ Authors: Kevin Buzzard, Richard M. Hill import Mathlib.Algebra.Polynomial.AlgebraMap import Mathlib.Algebra.Polynomial.Derivative import Mathlib.Algebra.Polynomial.Module.AEval +import Mathlib.RingTheory.Adjoin.Polynomial import Mathlib.RingTheory.Derivation.Basic /-! # Derivations of univariate polynomials diff --git a/Mathlib/Algebra/Polynomial/Div.lean b/Mathlib/Algebra/Polynomial/Div.lean index 804749c1a188a..41487703c5334 100644 --- a/Mathlib/Algebra/Polynomial/Div.lean +++ b/Mathlib/Algebra/Polynomial/Div.lean @@ -3,10 +3,11 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker -/ +import Mathlib.Algebra.Field.IsField import Mathlib.Algebra.Polynomial.Inductions import Mathlib.Algebra.Polynomial.Monic +import Mathlib.Algebra.Ring.Regular import Mathlib.RingTheory.Multiplicity -import Mathlib.RingTheory.Ideal.Maps /-! # Division of univariate polynomials @@ -16,7 +17,6 @@ The compatibility between these is given by `modByMonic_add_div`. We also define `rootMultiplicity`. -/ - noncomputable section open Polynomial @@ -53,8 +53,8 @@ theorem X_pow_dvd_iff {f : R[X]} {n : ℕ} : X ^ n ∣ f ↔ ∀ d < n, f.coeff variable {p q : R[X]} -theorem multiplicity_finite_of_degree_pos_of_monic (hp : (0 : WithBot ℕ) < degree p) (hmp : Monic p) - (hq : q ≠ 0) : multiplicity.Finite p q := +theorem finiteMultiplicity_of_degree_pos_of_monic (hp : (0 : WithBot ℕ) < degree p) (hmp : Monic p) + (hq : q ≠ 0) : FiniteMultiplicity p q := have zn0 : (0 : R) ≠ 1 := haveI := Nontrivial.of_polynomial_ne hq zero_ne_one @@ -76,6 +76,9 @@ theorem multiplicity_finite_of_degree_pos_of_monic (hp : (0 : WithBot ℕ) < deg (add_pos_of_pos_of_nonneg (by rwa [one_mul]) (Nat.zero_le _))) this⟩ +@[deprecated (since := "2024-11-30")] +alias multiplicity_finite_of_degree_pos_of_monic := finiteMultiplicity_of_degree_pos_of_monic + end Semiring section Ring @@ -349,7 +352,7 @@ theorem map_mod_divByMonic [Ring S] (f : R →+* S) (hq : Monic q) : div_modByMonic_unique ((p /ₘ q).map f) _ (hq.map f) ⟨Eq.symm <| by rw [← Polynomial.map_mul, ← Polynomial.map_add, modByMonic_add_div _ hq], calc - _ ≤ degree (p %ₘ q) := degree_map_le _ _ + _ ≤ degree (p %ₘ q) := degree_map_le _ < degree q := degree_modByMonic_lt _ hq _ = _ := Eq.symm <| @@ -431,7 +434,7 @@ lemma coeff_divByMonic_X_sub_C_rec (p : R[X]) (a : R) (n : ℕ) : rw [← p.modByMonic_add_div this] have : degree (p %ₘ (X - C a)) < ↑(n + 1) := degree_X_sub_C a ▸ p.degree_modByMonic_lt this |>.trans_le <| WithBot.coe_le_coe.mpr le_add_self - simp [sub_mul, add_sub, coeff_eq_zero_of_degree_lt this] + simp [q, sub_mul, add_sub, coeff_eq_zero_of_degree_lt this] theorem coeff_divByMonic_X_sub_C (p : R[X]) (a : R) (n : ℕ) : (p /ₘ (X - C a)).coeff n = ∑ i ∈ Icc (n + 1) p.natDegree, a ^ (i - (n + 1)) * p.coeff i := by @@ -470,12 +473,15 @@ See `polynomial.modByMonic` for the algorithm that computes `%ₘ`. def decidableDvdMonic [DecidableEq R] (p : R[X]) (hq : Monic q) : Decidable (q ∣ p) := decidable_of_iff (p %ₘ q = 0) (modByMonic_eq_zero_iff_dvd hq) -theorem multiplicity_X_sub_C_finite (a : R) (h0 : p ≠ 0) : multiplicity.Finite (X - C a) p := by +theorem finiteMultiplicity_X_sub_C (a : R) (h0 : p ≠ 0) : FiniteMultiplicity (X - C a) p := by haveI := Nontrivial.of_polynomial_ne h0 - refine multiplicity_finite_of_degree_pos_of_monic ?_ (monic_X_sub_C _) h0 + refine finiteMultiplicity_of_degree_pos_of_monic ?_ (monic_X_sub_C _) h0 rw [degree_X_sub_C] decide +@[deprecated (since := "2024-11-30")] +alias multiplicity_X_sub_C_finite := finiteMultiplicity_X_sub_C + /- Porting note: stripping out classical for decidability instance parameter might make for better ergonomics -/ /-- The largest power of `X - C a` which divides `p`. @@ -488,7 +494,7 @@ def rootMultiplicity (a : R) (p : R[X]) : ℕ := let _ : DecidablePred fun n : ℕ => ¬(X - C a) ^ (n + 1) ∣ p := fun n => have := decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1)) inferInstanceAs (Decidable ¬_) - Nat.find (multiplicity_X_sub_C_finite a h0) + Nat.find (finiteMultiplicity_X_sub_C a h0) /- Porting note: added the following due to diamond with decidableProp and decidableDvdMonic see also [Zulip] @@ -497,7 +503,7 @@ theorem rootMultiplicity_eq_nat_find_of_nonzero [DecidableEq R] {p : R[X]} (p0 : letI : DecidablePred fun n : ℕ => ¬(X - C a) ^ (n + 1) ∣ p := fun n => have := decidableDvdMonic p ((monic_X_sub_C a).pow (n + 1)) inferInstanceAs (Decidable ¬_) - rootMultiplicity a p = Nat.find (multiplicity_X_sub_C_finite a p0) := by + rootMultiplicity a p = Nat.find (finiteMultiplicity_X_sub_C a p0) := by dsimp [rootMultiplicity] cases Subsingleton.elim ‹DecidableEq R› (Classical.decEq R) rw [dif_neg p0] @@ -510,7 +516,7 @@ theorem rootMultiplicity_eq_multiplicity [DecidableEq R] split · rfl rename_i h - simp only [multiplicity_X_sub_C_finite a h, ↓reduceDIte] + simp only [finiteMultiplicity_X_sub_C a h, ↓reduceDIte] rw [← ENat.some_eq_coe, WithTop.untop'_coe] congr @@ -548,7 +554,7 @@ theorem exists_eq_pow_rootMultiplicity_mul_and_not_dvd (p : R[X]) (hp : p ≠ 0) ∃ q : R[X], p = (X - C a) ^ p.rootMultiplicity a * q ∧ ¬ (X - C a) ∣ q := by classical rw [rootMultiplicity_eq_multiplicity, if_neg hp] - apply (multiplicity_X_sub_C_finite a hp).exists_eq_pow_mul_and_not_dvd + apply (finiteMultiplicity_X_sub_C a hp).exists_eq_pow_mul_and_not_dvd end multiplicity @@ -592,16 +598,6 @@ theorem dvd_iff_isRoot : X - C a ∣ p ↔ IsRoot p a := theorem X_sub_C_dvd_sub_C_eval : X - C a ∣ p - C (p.eval a) := by rw [dvd_iff_isRoot, IsRoot, eval_sub, eval_C, sub_self] -theorem mem_span_C_X_sub_C_X_sub_C_iff_eval_eval_eq_zero {b : R[X]} {P : R[X][X]} : - P ∈ Ideal.span {C (X - C a), X - C b} ↔ (P.eval b).eval a = 0 := by - rw [Ideal.mem_span_pair] - constructor <;> intro h - · rcases h with ⟨_, _, rfl⟩ - simp only [eval_C, eval_X, eval_add, eval_sub, eval_mul, add_zero, mul_zero, sub_self] - · rcases dvd_iff_isRoot.mpr h with ⟨p, hp⟩ - rcases @X_sub_C_dvd_sub_C_eval _ b _ P with ⟨q, hq⟩ - exact ⟨C p, q, by rw [mul_comm, mul_comm q, eq_add_of_sub_eq' hq, hp, C_mul]⟩ - -- TODO: generalize this to Ring. In general, 0 can be replaced by any element in the center of R. theorem modByMonic_X (p : R[X]) : p %ₘ X = C (p.eval 0) := by rw [← modByMonic_X_sub_C_eq_C_eval, C_0, sub_zero] @@ -615,10 +611,6 @@ theorem sub_dvd_eval_sub (a b : R) (p : R[X]) : a - b ∣ p.eval a - p.eval b := simpa only [coe_evalRingHom, eval_sub, eval_X, eval_C] using (evalRingHom a).map_dvd this simp [dvd_iff_isRoot] -theorem ker_evalRingHom (x : R) : RingHom.ker (evalRingHom x) = Ideal.span {X - C x} := by - ext y - simp [Ideal.mem_span_singleton, dvd_iff_isRoot, RingHom.mem_ker] - @[simp] theorem rootMultiplicity_eq_zero_iff {p : R[X]} {x : R} : rootMultiplicity x p = 0 ↔ IsRoot p x → p = 0 := by @@ -647,7 +639,7 @@ theorem eval_divByMonic_pow_rootMultiplicity_ne_zero {p : R[X]} (a : R) (hp : p have := pow_mul_divByMonic_rootMultiplicity_eq p a rw [hq, ← mul_assoc, ← pow_succ, rootMultiplicity_eq_multiplicity, if_neg hp] at this exact - (multiplicity_finite_of_degree_pos_of_monic + (finiteMultiplicity_of_degree_pos_of_monic (show (0 : WithBot ℕ) < degree (X - C a) by rw [degree_X_sub_C]; decide) (monic_X_sub_C _) hp).not_pow_dvd_of_multiplicity_lt (Nat.lt_succ_self _) (dvd_of_mul_right_eq _ this) diff --git a/Mathlib/Algebra/Polynomial/Eval/Degree.lean b/Mathlib/Algebra/Polynomial/Eval/Degree.lean index 713aca85943c1..4105940c90547 100644 --- a/Mathlib/Algebra/Polynomial/Eval/Degree.lean +++ b/Mathlib/Algebra/Polynomial/Eval/Degree.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker -/ +import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.Algebra.Polynomial.Degree.Support import Mathlib.Algebra.Polynomial.Degree.Units import Mathlib.Algebra.Polynomial.Eval.Coeff @@ -107,29 +108,34 @@ theorem coeff_comp_degree_mul_degree (hqd0 : natDegree q ≠ 0) : case h₁ => simp +contextual +@[simp] lemma comp_C_mul_X_coeff {r : R} {n : ℕ} : + (p.comp <| C r * X).coeff n = p.coeff n * r ^ n := by + simp_rw [comp, eval₂_eq_sum_range, (commute_X _).symm.mul_pow, + ← C_pow, finset_sum_coeff, coeff_C_mul, coeff_X_pow] + rw [Finset.sum_eq_single n _ fun h ↦ ?_, if_pos rfl, mul_one] + · intro b _ h; simp_rw [if_neg h.symm, mul_zero] + · rw [coeff_eq_zero_of_natDegree_lt, zero_mul] + rwa [Finset.mem_range_succ_iff, not_le] at h + +lemma comp_C_mul_X_eq_zero_iff {r : R} (hr : r ∈ nonZeroDivisors R) : + p.comp (C r * X) = 0 ↔ p = 0 := by + simp_rw [ext_iff] + refine forall_congr' fun n ↦ ?_ + rw [comp_C_mul_X_coeff, coeff_zero, mul_right_mem_nonZeroDivisors_eq_zero_iff (pow_mem hr _)] + end Comp section Map -variable [Semiring S] -variable (f : R →+* S) +variable [Semiring S] {f : R →+* S} {p : R[X]} +variable (f) in /-- If `R` and `S` are isomorphic, then so are their polynomial rings. -/ @[simps!] def mapEquiv (e : R ≃+* S) : R[X] ≃+* S[X] := RingEquiv.ofHomInv (mapRingHom (e : R →+* S)) (mapRingHom (e.symm : S →+* R)) (by ext; simp) (by ext; simp) -theorem degree_map_le (p : R[X]) : degree (p.map f) ≤ degree p := by - refine (degree_le_iff_coeff_zero _ _).2 fun m hm => ?_ - rw [degree_lt_iff_coeff_zero] at hm - simp [hm m le_rfl] - -theorem natDegree_map_le (p : R[X]) : natDegree (p.map f) ≤ natDegree p := - natDegree_le_natDegree (degree_map_le f p) - -variable {f} - theorem map_monic_eq_zero_iff (hp : p.Monic) : p.map f = 0 ↔ ∀ x, f x = 0 := ⟨fun hfp x => calc @@ -142,15 +148,39 @@ theorem map_monic_eq_zero_iff (hp : p.Monic) : p.map f = 0 ↔ ∀ x, f x = 0 := theorem map_monic_ne_zero (hp : p.Monic) [Nontrivial S] : p.map f ≠ 0 := fun h => f.map_one_ne_zero ((map_monic_eq_zero_iff hp).mp h _) +lemma degree_map_le : degree (p.map f) ≤ degree p := by + refine (degree_le_iff_coeff_zero _ _).2 fun m hm => ?_ + rw [degree_lt_iff_coeff_zero] at hm + simp [hm m le_rfl] + +lemma natDegree_map_le : natDegree (p.map f) ≤ natDegree p := natDegree_le_natDegree degree_map_le + +lemma degree_map_lt (hp : f p.leadingCoeff = 0) (hp₀ : p ≠ 0) : (p.map f).degree < p.degree := by + refine degree_map_le.lt_of_ne fun hpq ↦ hp₀ ?_ + rw [leadingCoeff, ← coeff_map, ← natDegree_eq_natDegree hpq, ← leadingCoeff, leadingCoeff_eq_zero] + at hp + rw [← degree_eq_bot, ← hpq, hp, degree_zero] + +lemma natDegree_map_lt (hp : f p.leadingCoeff = 0) (hp₀ : map f p ≠ 0) : + (p.map f).natDegree < p.natDegree := + natDegree_lt_natDegree hp₀ <| degree_map_lt hp <| by rintro rfl; simp at hp₀ + +/-- Variant of `natDegree_map_lt` that assumes `0 < natDegree p` instead of `map f p ≠ 0`. -/ +lemma natDegree_map_lt' (hp : f p.leadingCoeff = 0) (hp₀ : 0 < natDegree p) : + (p.map f).natDegree < p.natDegree := by + by_cases H : map f p = 0 + · rwa [H, natDegree_zero] + · exact natDegree_map_lt hp H + theorem degree_map_eq_of_leadingCoeff_ne_zero (f : R →+* S) (hf : f (leadingCoeff p) ≠ 0) : - degree (p.map f) = degree p := - le_antisymm (degree_map_le f _) <| by - have hp0 : p ≠ 0 := - leadingCoeff_ne_zero.mp fun hp0 => hf (_root_.trans (congr_arg _ hp0) f.map_zero) - rw [degree_eq_natDegree hp0] - refine le_degree_of_ne_zero ?_ - rw [coeff_map] - exact hf + degree (p.map f) = degree p := by + refine degree_map_le.antisymm ?_ + have hp0 : p ≠ 0 := + leadingCoeff_ne_zero.mp fun hp0 => hf (_root_.trans (congr_arg _ hp0) f.map_zero) + rw [degree_eq_natDegree hp0] + refine le_degree_of_ne_zero ?_ + rw [coeff_map] + exact hf theorem natDegree_map_of_leadingCoeff_ne_zero (f : R →+* S) (hf : f (leadingCoeff p) ≠ 0) : natDegree (p.map f) = natDegree p := diff --git a/Mathlib/Algebra/Polynomial/FieldDivision.lean b/Mathlib/Algebra/Polynomial/FieldDivision.lean index bc0f49ad785ba..bb20dc5de2f78 100644 --- a/Mathlib/Algebra/Polynomial/FieldDivision.lean +++ b/Mathlib/Algebra/Polynomial/FieldDivision.lean @@ -175,11 +175,10 @@ See `isRoot_of_isRoot_iff_dvd_derivative_mul` -/ theorem isRoot_of_isRoot_of_dvd_derivative_mul [CharZero R] {f g : R[X]} (hf0 : f ≠ 0) (hfd : f ∣ f.derivative * g) {a : R} (haf : f.IsRoot a) : g.IsRoot a := by rcases hfd with ⟨r, hr⟩ - by_cases hdf0 : derivative f = 0 - · rw [eq_C_of_derivative_eq_zero hdf0] at haf hf0 - simp only [eval_C, derivative_C, zero_mul, dvd_zero, iff_true, IsRoot.def] at haf - rw [haf, map_zero] at hf0 - exact (hf0 rfl).elim + have hdf0 : derivative f ≠ 0 := by + contrapose! haf + rw [eq_C_of_derivative_eq_zero haf] at hf0 ⊢ + exact not_isRoot_C _ _ <| C_ne_zero.mp hf0 by_contra hg have hdfg0 : f.derivative * g ≠ 0 := mul_ne_zero hdf0 (by rintro rfl; simp at hg) have hr' := congr_arg (rootMultiplicity a) hr diff --git a/Mathlib/Algebra/Polynomial/Module/FiniteDimensional.lean b/Mathlib/Algebra/Polynomial/Module/FiniteDimensional.lean index faca138037327..0918dde79efba 100644 --- a/Mathlib/Algebra/Polynomial/Module/FiniteDimensional.lean +++ b/Mathlib/Algebra/Polynomial/Module/FiniteDimensional.lean @@ -5,6 +5,7 @@ Authors: Oliver Nash -/ import Mathlib.FieldTheory.Minpoly.Field import Mathlib.Algebra.Polynomial.Module.AEval +import Mathlib.Algebra.Module.Torsion /-! # Polynomial modules in finite dimensions diff --git a/Mathlib/Algebra/Polynomial/Monic.lean b/Mathlib/Algebra/Polynomial/Monic.lean index ee43be7d90efb..f78aa81f906ba 100644 --- a/Mathlib/Algebra/Polynomial/Monic.lean +++ b/Mathlib/Algebra/Polynomial/Monic.lean @@ -357,7 +357,7 @@ variable [Semiring R] @[simp] theorem Monic.natDegree_map [Semiring S] [Nontrivial S] {P : R[X]} (hmo : P.Monic) (f : R →+* S) : (P.map f).natDegree = P.natDegree := by - refine le_antisymm (natDegree_map_le _ _) (le_natDegree_of_ne_zero ?_) + refine le_antisymm natDegree_map_le (le_natDegree_of_ne_zero ?_) rw [coeff_map, Monic.coeff_natDegree hmo, RingHom.map_one] exact one_ne_zero @@ -366,7 +366,7 @@ theorem Monic.degree_map [Semiring S] [Nontrivial S] {P : R[X]} (hmo : P.Monic) (P.map f).degree = P.degree := by by_cases hP : P = 0 · simp [hP] - · refine le_antisymm (degree_map_le _ _) ?_ + · refine le_antisymm degree_map_le ?_ rw [degree_eq_natDegree hP] refine le_degree_of_ne_zero ?_ rw [coeff_map, Monic.coeff_natDegree hmo, RingHom.map_one] diff --git a/Mathlib/Algebra/Polynomial/PartialFractions.lean b/Mathlib/Algebra/Polynomial/PartialFractions.lean index e9bb4f3a58e49..35ee211386718 100644 --- a/Mathlib/Algebra/Polynomial/PartialFractions.lean +++ b/Mathlib/Algebra/Polynomial/PartialFractions.lean @@ -5,6 +5,7 @@ Authors: Kevin Buzzard, Sidharth Hariharan -/ import Mathlib.Algebra.Polynomial.Div import Mathlib.Logic.Function.Basic +import Mathlib.RingTheory.Coprime.Lemmas import Mathlib.RingTheory.Localization.FractionRing import Mathlib.Tactic.FieldSimp import Mathlib.Tactic.LinearCombination diff --git a/Mathlib/Algebra/Polynomial/RingDivision.lean b/Mathlib/Algebra/Polynomial/RingDivision.lean index ca3c0ccfff641..ad3c8e6a0e543 100644 --- a/Mathlib/Algebra/Polynomial/RingDivision.lean +++ b/Mathlib/Algebra/Polynomial/RingDivision.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker, Johan Commelin -/ import Mathlib.Algebra.Polynomial.AlgebraMap -import Mathlib.Algebra.Polynomial.Degree.Lemmas import Mathlib.Algebra.Polynomial.Div +import Mathlib.RingTheory.Coprime.Basic /-! # Theory of univariate polynomials @@ -14,6 +14,8 @@ We prove basic results about univariate polynomials. -/ +assert_not_exists Ideal.map + noncomputable section open Polynomial @@ -65,11 +67,6 @@ theorem mem_ker_modByMonic (hq : q.Monic) {p : R[X]} : p ∈ LinearMap.ker (modByMonicHom q) ↔ q ∣ p := LinearMap.mem_ker.trans (modByMonic_eq_zero_iff_dvd hq) -@[simp] -theorem ker_modByMonicHom (hq : q.Monic) : - LinearMap.ker (Polynomial.modByMonicHom q) = (Ideal.span {q}).restrictScalars R := - Submodule.ext fun _ => (mem_ker_modByMonic hq).trans Ideal.mem_span_singleton.symm - section variable [Ring S] @@ -233,7 +230,7 @@ theorem rootMultiplicity_mul {p q : R[X]} {x : R} (hpq : p * q ≠ 0) : have hq : q ≠ 0 := right_ne_zero_of_mul hpq rw [rootMultiplicity_eq_multiplicity (p * q), if_neg hpq, rootMultiplicity_eq_multiplicity p, if_neg hp, rootMultiplicity_eq_multiplicity q, if_neg hq, - multiplicity_mul (prime_X_sub_C x) (multiplicity_X_sub_C_finite _ hpq)] + multiplicity_mul (prime_X_sub_C x) (finiteMultiplicity_X_sub_C _ hpq)] open Multiset in set_option linter.unusedVariables false in diff --git a/Mathlib/Algebra/Polynomial/Roots.lean b/Mathlib/Algebra/Polynomial/Roots.lean index d2a32fe42bc6e..12df720582d0e 100644 --- a/Mathlib/Algebra/Polynomial/Roots.lean +++ b/Mathlib/Algebra/Polynomial/Roots.lean @@ -5,8 +5,8 @@ Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker, Johan Comm -/ import Mathlib.Algebra.Polynomial.BigOperators import Mathlib.Algebra.Polynomial.RingDivision -import Mathlib.Data.Fintype.Pi import Mathlib.Data.Set.Finite.Lemmas +import Mathlib.RingTheory.Coprime.Lemmas import Mathlib.RingTheory.Localization.FractionRing import Mathlib.SetTheory.Cardinal.Basic @@ -29,6 +29,8 @@ We define the multiset of roots of a polynomial, and prove basic results about i -/ +assert_not_exists Ideal + open Multiset Finset noncomputable section @@ -749,7 +751,17 @@ theorem roots_map_of_injective_of_card_eq_natDegree [IsDomain A] [IsDomain B] {p {f : A →+* B} (hf : Function.Injective f) (hroots : Multiset.card p.roots = p.natDegree) : p.roots.map f = (p.map f).roots := by apply Multiset.eq_of_le_of_card_le (map_roots_le_of_injective p hf) - simpa only [Multiset.card_map, hroots] using (card_roots' _).trans (natDegree_map_le f p) + simpa only [Multiset.card_map, hroots] using (card_roots' _).trans natDegree_map_le + +theorem roots_map_of_map_ne_zero_of_card_eq_natDegree [IsDomain A] [IsDomain B] {p : A[X]} + (f : A →+* B) (h : p.map f ≠ 0) (hroots : p.roots.card = p.natDegree) : + p.roots.map f = (p.map f).roots := + eq_of_le_of_card_le (map_roots_le h) <| by + simpa only [Multiset.card_map, hroots] using (p.map f).card_roots'.trans natDegree_map_le + +theorem Monic.roots_map_of_card_eq_natDegree [IsDomain A] [IsDomain B] {p : A[X]} (hm : p.Monic) + (f : A →+* B) (hroots : p.roots.card = p.natDegree) : p.roots.map f = (p.map f).roots := + roots_map_of_map_ne_zero_of_card_eq_natDegree f (map_monic_ne_zero hm) hroots end diff --git a/Mathlib/Algebra/Polynomial/Splits.lean b/Mathlib/Algebra/Polynomial/Splits.lean index 211e8294de371..eb94c89f217df 100644 --- a/Mathlib/Algebra/Polynomial/Splits.lean +++ b/Mathlib/Algebra/Polynomial/Splits.lean @@ -6,6 +6,7 @@ Authors: Chris Hughes import Mathlib.Algebra.Polynomial.FieldDivision import Mathlib.Algebra.Polynomial.Lifts import Mathlib.Data.List.Prime +import Mathlib.RingTheory.Adjoin.Basic import Mathlib.RingTheory.Polynomial.Tower /-! @@ -77,7 +78,7 @@ theorem splits_of_degree_le_one {f : K[X]} (hf : degree f ≤ 1) : Splits i f := else by push_neg at hif rw [← Order.succ_le_iff, ← WithBot.coe_zero, WithBot.succ_coe, Nat.succ_eq_succ] at hif - exact splits_of_map_degree_eq_one i (le_antisymm ((degree_map_le i _).trans hf) hif) + exact splits_of_map_degree_eq_one i ((degree_map_le.trans hf).antisymm hif) theorem splits_of_degree_eq_one {f : K[X]} (hf : degree f = 1) : Splits i f := splits_of_degree_le_one i hf.le @@ -189,7 +190,7 @@ but its conditions are easier to check. -/ theorem Splits.comp_of_degree_le_one {f : K[X]} {p : K[X]} (hd : p.degree ≤ 1) (h : f.Splits i) : (f.comp p).Splits i := - Splits.comp_of_map_degree_le_one ((degree_map_le i _).trans hd) h + Splits.comp_of_map_degree_le_one (degree_map_le.trans hd) h theorem Splits.comp_X_sub_C (a : K) {f : K[X]} (h : f.Splits i) : (f.comp (X - C a)).Splits i := diff --git a/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean b/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean index f05a9ab0735d1..890f08beece92 100644 --- a/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean +++ b/Mathlib/Algebra/Polynomial/SumIteratedDerivative.lean @@ -217,14 +217,17 @@ theorem aeval_sumIDeriv_of_pos [Nontrivial A] [NoZeroDivisors A] (p : R[X]) {q : intro r p' hp have : range (p.natDegree + 1) = range q ∪ Ico q (p.natDegree + 1) := by rw [range_eq_Ico, Ico_union_Ico_eq_Ico hq.le] - have h := natDegree_map_le (algebraMap R A) p - rw [congr_arg natDegree hp, natDegree_mul, natDegree_pow, natDegree_X_sub_C, mul_one, - ← Nat.sub_add_comm (Nat.one_le_of_lt hq), tsub_le_iff_right] at h - exact le_of_add_le_left h - · exact pow_ne_zero _ (X_sub_C_ne_zero r) - · rintro rfl - rw [mul_zero, Polynomial.map_eq_zero_iff inj_amap] at hp - exact p0 hp + rw [← tsub_le_iff_right] + calc + q - 1 ≤ q - 1 + p'.natDegree := le_self_add + _ = (p.map <| algebraMap R A).natDegree := by + rw [hp, natDegree_mul, natDegree_pow, natDegree_X_sub_C, mul_one, + ← Nat.sub_add_comm (Nat.one_le_of_lt hq)] + · exact pow_ne_zero _ (X_sub_C_ne_zero r) + · rintro rfl + rw [mul_zero, Polynomial.map_eq_zero_iff inj_amap] at hp + exact p0 hp + _ ≤ p.natDegree := natDegree_map_le rw [← zero_add ((q - 1)! • p'.eval r)] rw [sumIDeriv_apply, map_sum, map_sum, this] have : range q = range (q - 1 + 1) := by rw [tsub_add_cancel_of_le (Nat.one_le_of_lt hq)] diff --git a/Mathlib/Algebra/Prime/Lemmas.lean b/Mathlib/Algebra/Prime/Lemmas.lean index 0211c3bbc8c5e..1df2748e62898 100644 --- a/Mathlib/Algebra/Prime/Lemmas.lean +++ b/Mathlib/Algebra/Prime/Lemmas.lean @@ -3,6 +3,7 @@ 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.Hom import Mathlib.Algebra.Group.Commute.Units import Mathlib.Algebra.Group.Even import Mathlib.Algebra.Group.Units.Equiv diff --git a/Mathlib/Algebra/Quandle.lean b/Mathlib/Algebra/Quandle.lean index d02c6b1972aa1..fb77c232c8337 100644 --- a/Mathlib/Algebra/Quandle.lean +++ b/Mathlib/Algebra/Quandle.lean @@ -417,7 +417,6 @@ def Conj.map {G : Type*} {H : Type*} [Group G] [Group H] (f : G →* H) : Conj G Used for Fox n-colorings of knots. -/ --- Porting note: Removed nolint def Dihedral (n : ℕ) := ZMod n diff --git a/Mathlib/Algebra/Quaternion.lean b/Mathlib/Algebra/Quaternion.lean index 1ee91c3592cc2..9a6904b709e90 100644 --- a/Mathlib/Algebra/Quaternion.lean +++ b/Mathlib/Algebra/Quaternion.lean @@ -148,7 +148,7 @@ theorem coe_injective : Function.Injective (coe : R → ℍ[R,c₁,c₂]) := fun theorem coe_inj {x y : R} : (x : ℍ[R,c₁,c₂]) = y ↔ x = y := coe_injective.eq_iff --- Porting note: removed `simps`, added simp lemmas manually +-- Porting note: removed `simps`, added simp lemmas manually. Should adjust `simps` to name properly instance : Zero ℍ[R,c₁,c₂] := ⟨⟨0, 0, 0, 0⟩⟩ @[simp] theorem zero_re : (0 : ℍ[R,c₁,c₂]).re = 0 := rfl @@ -169,7 +169,7 @@ instance : Inhabited ℍ[R,c₁,c₂] := ⟨0⟩ section One variable [One R] --- Porting note: removed `simps`, added simp lemmas manually +-- Porting note: removed `simps`, added simp lemmas manually. Should adjust `simps` to name properly instance : One ℍ[R,c₁,c₂] := ⟨⟨1, 0, 0, 0⟩⟩ @[simp] theorem one_re : (1 : ℍ[R,c₁,c₂]).re = 1 := rfl @@ -190,7 +190,7 @@ end Zero section Add variable [Add R] --- Porting note: removed `simps`, added simp lemmas manually +-- Porting note: removed `simps`, added simp lemmas manually. Should adjust `simps` to name properly instance : Add ℍ[R,c₁,c₂] := ⟨fun a b => ⟨a.1 + b.1, a.2 + b.2, a.3 + b.3, a.4 + b.4⟩⟩ @@ -223,7 +223,7 @@ end AddZeroClass section Neg variable [Neg R] --- Porting note: removed `simps`, added simp lemmas manually +-- Porting note: removed `simps`, added simp lemmas manually. Should adjust `simps` to name properly instance : Neg ℍ[R,c₁,c₂] := ⟨fun a => ⟨-a.1, -a.2, -a.3, -a.4⟩⟩ @[simp] theorem neg_re : (-a).re = -a.re := rfl @@ -718,6 +718,7 @@ end QuaternionAlgebra def Quaternion (R : Type*) [One R] [Neg R] := QuaternionAlgebra R (-1) (-1) +@[inherit_doc] scoped[Quaternion] notation "ℍ[" R "]" => Quaternion R /-- The equivalence between the quaternions over `R` and `R × R × R × R`. -/ @@ -744,8 +745,6 @@ namespace Quaternion variable {S T R : Type*} [CommRing R] (r x y : R) (a b : ℍ[R]) -export QuaternionAlgebra (re imI imJ imK) - /-- Coercion `R → ℍ[R]`. -/ @[coe] def coe : R → ℍ[R] := QuaternionAlgebra.coe @@ -1191,7 +1190,7 @@ theorem normSq_le_zero : normSq a ≤ 0 ↔ a = 0 := normSq_nonneg.le_iff_eq.trans normSq_eq_zero instance instNontrivial : Nontrivial ℍ[R] where - exists_pair_ne := ⟨0, 1, mt (congr_arg re) zero_ne_one⟩ + exists_pair_ne := ⟨0, 1, mt (congr_arg QuaternionAlgebra.re) zero_ne_one⟩ instance : NoZeroDivisors ℍ[R] where eq_zero_or_eq_zero_of_mul_eq_zero {a b} hab := @@ -1226,8 +1225,6 @@ instance instGroupWithZero : GroupWithZero ℍ[R] := inv := Inv.inv inv_zero := by rw [instInv_inv, star_zero, smul_zero] mul_inv_cancel := fun a ha => by - -- Porting note: the aliased definition confuse TC search - letI : Semiring ℍ[R] := inferInstanceAs (Semiring ℍ[R,-1,-1]) rw [instInv_inv, Algebra.mul_smul_comm (normSq a)⁻¹ a (star a), self_mul_star, smul_coe, inv_mul_cancel₀ (normSq_ne_zero.2 ha), coe_one] } diff --git a/Mathlib/Algebra/Ring/Basic.lean b/Mathlib/Algebra/Ring/Basic.lean index fd10db100aadd..1682f8c413b9e 100644 --- a/Mathlib/Algebra/Ring/Basic.lean +++ b/Mathlib/Algebra/Ring/Basic.lean @@ -124,37 +124,25 @@ section NoZeroDivisors variable (α) -lemma IsLeftCancelMulZero.to_noZeroDivisors [NonUnitalNonAssocRing α] [IsLeftCancelMulZero α] : - NoZeroDivisors α := - { eq_zero_or_eq_zero_of_mul_eq_zero := fun {x y} h ↦ by - by_cases hx : x = 0 - { left - exact hx } - { right - rw [← sub_zero (x * y), ← mul_zero x, ← mul_sub] at h - have := (IsLeftCancelMulZero.mul_left_cancel_of_ne_zero) hx h - rwa [sub_zero] at this } } - -lemma IsRightCancelMulZero.to_noZeroDivisors [NonUnitalNonAssocRing α] [IsRightCancelMulZero α] : - NoZeroDivisors α := - { eq_zero_or_eq_zero_of_mul_eq_zero := fun {x y} h ↦ by - by_cases hy : y = 0 - { right - exact hy } - { left - rw [← sub_zero (x * y), ← zero_mul y, ← sub_mul] at h - have := (IsRightCancelMulZero.mul_right_cancel_of_ne_zero) hy h - rwa [sub_zero] at this } } +lemma IsLeftCancelMulZero.to_noZeroDivisors [NonUnitalNonAssocSemiring α] + [IsLeftCancelMulZero α] : NoZeroDivisors α where + eq_zero_or_eq_zero_of_mul_eq_zero {x _} h := + or_iff_not_imp_left.mpr fun ne ↦ mul_left_cancel₀ ne ((mul_zero x).symm ▸ h) + +lemma IsRightCancelMulZero.to_noZeroDivisors [NonUnitalNonAssocSemiring α] + [IsRightCancelMulZero α] : NoZeroDivisors α where + eq_zero_or_eq_zero_of_mul_eq_zero {_ y} h := + or_iff_not_imp_right.mpr fun ne ↦ mul_right_cancel₀ ne ((zero_mul y).symm ▸ h) instance (priority := 100) NoZeroDivisors.to_isCancelMulZero [NonUnitalNonAssocRing α] [NoZeroDivisors α] : - IsCancelMulZero α := - { mul_left_cancel_of_ne_zero := fun 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 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) } + IsCancelMulZero α where + mul_left_cancel_of_ne_zero 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 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) /-- In a ring, `IsCancelMulZero` and `NoZeroDivisors` are equivalent. -/ lemma isCancelMulZero_iff_noZeroDivisors [NonUnitalNonAssocRing α] : @@ -165,7 +153,7 @@ lemma NoZeroDivisors.to_isDomain [Ring α] [h : Nontrivial α] [NoZeroDivisors IsDomain α := { NoZeroDivisors.to_isCancelMulZero α, h with .. } -instance (priority := 100) IsDomain.to_noZeroDivisors [Ring α] [IsDomain α] : +instance (priority := 100) IsDomain.to_noZeroDivisors [Semiring α] [IsDomain α] : NoZeroDivisors α := IsRightCancelMulZero.to_noZeroDivisors α diff --git a/Mathlib/Algebra/Ring/Divisibility/Basic.lean b/Mathlib/Algebra/Ring/Divisibility/Basic.lean index dbe11489b614e..1f2823ca80b9c 100644 --- a/Mathlib/Algebra/Ring/Divisibility/Basic.lean +++ b/Mathlib/Algebra/Ring/Divisibility/Basic.lean @@ -3,7 +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, Floris van Doorn, Yury Kudryashov, Neil Strickland -/ -import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Divisibility.Hom import Mathlib.Algebra.Group.Equiv.Basic import Mathlib.Algebra.Ring.Defs diff --git a/Mathlib/Algebra/Ring/Hom/Basic.lean b/Mathlib/Algebra/Ring/Hom/Basic.lean index 66e709402768d..10cf5b59b7a95 100644 --- a/Mathlib/Algebra/Ring/Hom/Basic.lean +++ b/Mathlib/Algebra/Ring/Hom/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2019 Amelia Livingston. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Amelia Livingston, Jireh Loreaux -/ -import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Divisibility.Hom import Mathlib.Algebra.GroupWithZero.InjSurj import Mathlib.Algebra.Ring.Hom.Defs import Mathlib.Data.Set.Basic @@ -49,9 +49,7 @@ end Semiring end RingHom /-- Pullback `IsDomain` instance along an injective function. -/ -protected theorem Function.Injective.isDomain [Ring α] [IsDomain α] [Ring β] (f : β →+* α) - (hf : Injective f) : IsDomain β := by - haveI := pullback_nonzero f f.map_zero f.map_one - haveI := IsRightCancelMulZero.to_noZeroDivisors α - haveI := hf.noZeroDivisors f f.map_zero f.map_mul - exact NoZeroDivisors.to_isDomain β +protected theorem Function.Injective.isDomain [Semiring α] [IsDomain α] [Semiring β] {F} + [FunLike F β α] [MonoidWithZeroHomClass F β α] (f : F) (hf : Injective f) : IsDomain β where + __ := domain_nontrivial f (map_zero _) (map_one _) + __ := hf.isCancelMulZero f (map_zero _) (map_mul _) diff --git a/Mathlib/Algebra/Ring/Subring/Basic.lean b/Mathlib/Algebra/Ring/Subring/Basic.lean index 791ac77d64f46..d81eb33fca30f 100644 --- a/Mathlib/Algebra/Ring/Subring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subring/Basic.lean @@ -66,6 +66,7 @@ variable {R : Type u} {S : Type v} {T : Type w} [Ring R] variable [Ring S] [Ring T] namespace Subring +variable {s t : Subring R} -- Porting note: there is no `Subring.toSubmonoid` but we can't define it because there is a -- projection `s.toSubmonoid` @@ -78,6 +79,12 @@ theorem toSubsemiring_strictMono : StrictMono (toSubsemiring : Subring R → Sub theorem toSubsemiring_mono : Monotone (toSubsemiring : Subring R → Subsemiring R) := toSubsemiring_strictMono.monotone +@[gcongr] +lemma toSubsemiring_lt_toSubsemiring (hst : s < t) : s.toSubsemiring < t.toSubsemiring := hst + +@[gcongr] +lemma toSubsemiring_le_toSubsemiring (hst : s ≤ t) : s.toSubsemiring ≤ t.toSubsemiring := hst + @[mono] theorem toAddSubgroup_strictMono : StrictMono (toAddSubgroup : Subring R → AddSubgroup R) := fun _ _ => id @@ -86,6 +93,12 @@ theorem toAddSubgroup_strictMono : StrictMono (toAddSubgroup : Subring R → Add theorem toAddSubgroup_mono : Monotone (toAddSubgroup : Subring R → AddSubgroup R) := toAddSubgroup_strictMono.monotone +@[gcongr] +lemma toAddSubgroup_lt_toAddSubgroup (hst : s < t) : s.toAddSubgroup < t.toAddSubgroup := hst + +@[gcongr] +lemma toAddSubgroup_le_toAddSubgroup (hst : s ≤ t) : s.toAddSubgroup ≤ t.toAddSubgroup := hst + @[mono] theorem toSubmonoid_strictMono : StrictMono (fun s : Subring R => s.toSubmonoid) := fun _ _ => id @@ -460,6 +473,7 @@ theorem closure_le {s : Set R} {t : Subring R} : closure s ≤ t ↔ s ⊆ t := /-- Subring closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set R⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Set.Subset.trans h subset_closure @@ -655,7 +669,7 @@ theorem coe_prod (s : Subring R) (t : Subring S) : theorem mem_prod {s : Subring R} {t : Subring S} {p : R × S} : p ∈ s.prod t ↔ p.1 ∈ s ∧ p.2 ∈ t := Iff.rfl -@[mono] +@[gcongr, mono] theorem prod_mono ⦃s₁ s₂ : Subring R⦄ (hs : s₁ ≤ s₂) ⦃t₁ t₂ : Subring S⦄ (ht : t₁ ≤ t₂) : s₁.prod t₁ ≤ s₂.prod t₂ := Set.prod_mono hs ht diff --git a/Mathlib/Algebra/Ring/Subring/Defs.lean b/Mathlib/Algebra/Ring/Subring/Defs.lean index 653ae172134f9..3b201ab0ecd61 100644 --- a/Mathlib/Algebra/Ring/Subring/Defs.lean +++ b/Mathlib/Algebra/Ring/Subring/Defs.lean @@ -98,15 +98,16 @@ instance (priority := 75) toHasIntCast : IntCast s := -- Prefer subclasses of `Ring` over subclasses of `SubringClass`. /-- A subring of a ring inherits a ring structure -/ instance (priority := 75) toRing : Ring s := - Subtype.coe_injective.ring (↑) rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) + Subtype.coe_injective.ring Subtype.val rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl -- Prefer subclasses of `Ring` over subclasses of `SubringClass`. /-- A subring of a `CommRing` is a `CommRing`. -/ instance (priority := 75) toCommRing {R} [CommRing R] [SetLike S R] [SubringClass S R] : CommRing s := - Subtype.coe_injective.commRing (↑) rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) - (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ => rfl) fun _ => rfl + Subtype.coe_injective.commRing Subtype.val rfl rfl (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) (fun _ _ => rfl) + (fun _ => rfl) fun _ => rfl -- Prefer subclasses of `Ring` over subclasses of `SubringClass`. /-- A subring of a domain is a domain. -/ diff --git a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean index bcd9bb5829c17..88035633f260c 100644 --- a/Mathlib/Algebra/Ring/Subsemiring/Basic.lean +++ b/Mathlib/Algebra/Ring/Subsemiring/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Yury Kudryashov. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ -import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Module.RingHom import Mathlib.Algebra.Ring.Action.Subobjects import Mathlib.Algebra.Ring.Equiv @@ -357,6 +357,7 @@ theorem closure_le {s : Set R} {t : Subsemiring R} : closure s ≤ t ↔ s ⊆ t /-- Subsemiring closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set R⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Set.Subset.trans h subset_closure @@ -588,7 +589,7 @@ theorem mem_prod {s : Subsemiring R} {t : Subsemiring S} {p : R × S} : p ∈ s.prod t ↔ p.1 ∈ s ∧ p.2 ∈ t := Iff.rfl -@[mono] +@[gcongr, mono] theorem prod_mono ⦃s₁ s₂ : Subsemiring R⦄ (hs : s₁ ≤ s₂) ⦃t₁ t₂ : Subsemiring S⦄ (ht : t₁ ≤ t₂) : s₁.prod t₁ ≤ s₂.prod t₂ := Set.prod_mono hs ht diff --git a/Mathlib/Algebra/Squarefree/Basic.lean b/Mathlib/Algebra/Squarefree/Basic.lean index 9d68d11fc173a..bdc6c55ec4a16 100644 --- a/Mathlib/Algebra/Squarefree/Basic.lean +++ b/Mathlib/Algebra/Squarefree/Basic.lean @@ -103,13 +103,7 @@ theorem Squarefree.gcd_left {a : α} (b : α) (ha : Squarefree a) : Squarefree ( end SquarefreeGcdOfSquarefree -namespace multiplicity - -section CommMonoid - -variable [CommMonoid R] - -theorem squarefree_iff_emultiplicity_le_one (r : R) : +theorem squarefree_iff_emultiplicity_le_one [CommMonoid R] (r : R) : Squarefree r ↔ ∀ x : R, emultiplicity x r ≤ 1 ∨ IsUnit x := by refine forall_congr' fun a => ?_ rw [← sq, pow_dvd_iff_le_emultiplicity, or_iff_not_imp_left, not_le, imp_congr _ Iff.rfl] @@ -117,18 +111,8 @@ theorem squarefree_iff_emultiplicity_le_one (r : R) : rw [← one_add_one_eq_two] exact Order.add_one_le_iff_of_not_isMax (by simp) -end CommMonoid - -section CancelCommMonoidWithZero - -variable [CancelCommMonoidWithZero R] [WfDvdMonoid R] - -theorem finite_prime_left {a b : R} (ha : Prime a) (hb : b ≠ 0) : multiplicity.Finite a b := - finite_of_not_isUnit ha.not_unit hb - -end CancelCommMonoidWithZero - -end multiplicity +@[deprecated (since := "2024-11-30")] +alias multiplicity.squarefree_iff_emultiplicity_le_one := squarefree_iff_emultiplicity_le_one section Irreducible @@ -266,7 +250,7 @@ lemma _root_.exists_squarefree_dvd_pow_of_ne_zero {x : R} (hx : x ≠ 0) : theorem squarefree_iff_nodup_normalizedFactors [NormalizationMonoid R] {x : R} (x0 : x ≠ 0) : Squarefree x ↔ Multiset.Nodup (normalizedFactors x) := by classical - rw [multiplicity.squarefree_iff_emultiplicity_le_one, Multiset.nodup_iff_count_le_one] + rw [squarefree_iff_emultiplicity_le_one, Multiset.nodup_iff_count_le_one] haveI := nontrivial_of_ne x 0 x0 constructor <;> intro h a · by_cases hmem : a ∈ normalizedFactors x diff --git a/Mathlib/Algebra/TrivSqZeroExt.lean b/Mathlib/Algebra/TrivSqZeroExt.lean index cc4239ab85e25..fd15145d858ba 100644 --- a/Mathlib/Algebra/TrivSqZeroExt.lean +++ b/Mathlib/Algebra/TrivSqZeroExt.lean @@ -6,6 +6,7 @@ Authors: Kenny Lau, Eric Wieser import Mathlib.Algebra.Algebra.Defs import Mathlib.Algebra.BigOperators.GroupWithZero.Action import Mathlib.LinearAlgebra.Prod +import Mathlib.Algebra.BigOperators.Pi /-! # Trivial Square-Zero Extension diff --git a/Mathlib/Algebra/Tropical/Basic.lean b/Mathlib/Algebra/Tropical/Basic.lean index 5a22f3bbfe005..dfb67530f2fc9 100644 --- a/Mathlib/Algebra/Tropical/Basic.lean +++ b/Mathlib/Algebra/Tropical/Basic.lean @@ -6,8 +6,10 @@ Authors: Yakov Pechersky import Mathlib.Algebra.Order.Monoid.Unbundled.Pow import Mathlib.Algebra.SMulWithZero import Mathlib.Order.Hom.Basic -import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Algebra.Order.Monoid.Unbundled.WithTop +import Mathlib.Algebra.Order.AddGroupWithTop +import Mathlib.Algebra.Ring.Nat +import Mathlib.Algebra.Order.Monoid.Unbundled.MinMax /-! diff --git a/Mathlib/Algebra/Vertex/HVertexOperator.lean b/Mathlib/Algebra/Vertex/HVertexOperator.lean index 4248cbf1e971d..d68241ff4baf6 100644 --- a/Mathlib/Algebra/Vertex/HVertexOperator.lean +++ b/Mathlib/Algebra/Vertex/HVertexOperator.lean @@ -92,6 +92,16 @@ def of_coeff (f : Γ → V →ₗ[R] W) @[deprecated (since := "2024-06-18")] alias _root_.VertexAlg.HetVertexOperator.of_coeff := of_coeff +@[simp] +theorem add_coeff (A B : HVertexOperator Γ R V W) : (A + B).coeff = A.coeff + B.coeff := by + ext + simp + +@[simp] +theorem smul_coeff (A : HVertexOperator Γ R V W) (r : R) : (r • A).coeff = r • (A.coeff) := by + ext + simp + end Coeff section Products diff --git a/Mathlib/Algebra/Vertex/VertexOperator.lean b/Mathlib/Algebra/Vertex/VertexOperator.lean new file mode 100644 index 0000000000000..e7eaef0b16c08 --- /dev/null +++ b/Mathlib/Algebra/Vertex/VertexOperator.lean @@ -0,0 +1,99 @@ +/- +Copyright (c) 2024 Scott Carnahan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Carnahan +-/ +import Mathlib.Algebra.Vertex.HVertexOperator +import Mathlib.Data.Int.Interval + +/-! +# Vertex operators +In this file we introduce vertex operators as linear maps to Laurent series. + +## Definitions + * `VertexOperator` is an `R`-linear map from an `R`-module `V` to `LaurentSeries V`. + * `VertexOperator.ncoeff` is the coefficient of a vertex operator under normalized indexing. + +## TODO + * `HasseDerivative` : A divided-power derivative. + * `Locality` : A weak form of commutativity. + * `Residue products` : A family of products on `VertexOperator R V` parametrized by integers. + +## References + * [G. Mason, *Vertex rings and Pierce bundles*][mason2017] + * [A. Matsuo, K. Nagatomo, *On axioms for a vertex algebra and locality of quantum + fields*][matsuo1997] +-/ + +noncomputable section + +variable {R V : Type*} [CommRing R] [AddCommGroup V] [Module R V] + +/-- A vertex operator over a commutative ring `R` is an `R`-linear map from an `R`-module `V` to +Laurent series with coefficients in `V`. We write this as a specialization of the heterogeneous +case. -/ +abbrev VertexOperator (R : Type*) (V : Type*) [CommRing R] [AddCommGroup V] + [Module R V] := HVertexOperator ℤ R V V + +namespace VertexOperator + +open HVertexOperator + +@[ext] +theorem ext (A B : VertexOperator R V) (h : ∀ v : V, A v = B v) : + A = B := LinearMap.ext h + +/-- The coefficient of a vertex operator under normalized indexing. -/ +def ncoeff {R} [CommRing R] [AddCommGroup V] [Module R V] (A : VertexOperator R V) (n : ℤ) : + Module.End R V := HVertexOperator.coeff A (-n - 1) + +/-- In the literature, the `n`th normalized coefficient of a vertex operator `A` is written as +either `Aₙ` or `A(n)`. -/ +scoped[VertexOperator] notation A "[[" n "]]" => ncoeff A n + +@[simp] +theorem coeff_eq_ncoeff (A : VertexOperator R V) + (n : ℤ) : HVertexOperator.coeff A n = A [[-n - 1]] := by + rw [ncoeff, neg_sub, sub_neg_eq_add, add_sub_cancel_left] + +@[simp] +theorem ncoeff_add (A B : VertexOperator R V) (n : ℤ) : (A + B) [[n]] = A [[n]] + B [[n]] := by + rw [ncoeff, ncoeff, ncoeff, add_coeff, Pi.add_apply] + +@[simp] +theorem ncoeff_smul (A : VertexOperator R V) (r : R) (n : ℤ) : (r • A) [[n]] = r • A [[n]] := by + rw [ncoeff, ncoeff, smul_coeff, Pi.smul_apply] + +theorem ncoeff_eq_zero_of_lt_order (A : VertexOperator R V) (n : ℤ) (x : V) + (h : -n - 1 < HahnSeries.order ((HahnModule.of R).symm (A x))) : (A [[n]]) x = 0 := by + simp only [ncoeff, HVertexOperator.coeff, LinearMap.coe_mk, AddHom.coe_mk] + exact HahnSeries.coeff_eq_zero_of_lt_order h + +theorem coeff_eq_zero_of_lt_order (A : VertexOperator R V) (n : ℤ) (x : V) + (h : n < HahnSeries.order ((HahnModule.of R).symm (A x))) : coeff A n x = 0 := by + rw [coeff_eq_ncoeff, ncoeff_eq_zero_of_lt_order A (-n - 1) x] + omega + +/-- Given an endomorphism-valued function on integers satisfying a pointwise bounded-pole condition, +we produce a vertex operator. -/ +noncomputable def of_coeff (f : ℤ → Module.End R V) + (hf : ∀ (x : V), ∃ (n : ℤ), ∀ (m : ℤ), m < n → (f m) x = 0) : VertexOperator R V := + HVertexOperator.of_coeff f + (fun x => HahnSeries.suppBddBelow_supp_PWO (fun n => (f n) x) + (HahnSeries.forallLTEqZero_supp_BddBelow (fun n => (f n) x) + (Exists.choose (hf x)) (Exists.choose_spec (hf x)))) + +@[simp] +theorem of_coeff_apply_coeff (f : ℤ → Module.End R V) + (hf : ∀ (x : V), ∃ n, ∀ m < n, (f m) x = 0) (x : V) (n : ℤ) : + ((HahnModule.of R).symm ((of_coeff f hf) x)).coeff n = (f n) x := by + rfl + +@[simp] +theorem ncoeff_of_coeff (f : ℤ → Module.End R V) + (hf : ∀(x : V), ∃(n : ℤ), ∀(m : ℤ), m < n → (f m) x = 0) (n : ℤ) : + (of_coeff f hf) [[n]] = f (-n - 1) := by + ext v + rw [ncoeff, coeff_apply, of_coeff_apply_coeff] + +end VertexOperator diff --git a/Mathlib/AlgebraicGeometry/AffineSpace.lean b/Mathlib/AlgebraicGeometry/AffineSpace.lean index 805e43c4928d2..ac5248a0b208b 100644 --- a/Mathlib/AlgebraicGeometry/AffineSpace.lean +++ b/Mathlib/AlgebraicGeometry/AffineSpace.lean @@ -295,9 +295,7 @@ lemma map_comp {S S' S'' : Scheme} (f : S ⟶ S') (g : S' ⟶ S'') : map n (f ≫ g) = map n f ≫ map n g := by ext1 · simp - · simp only [TopologicalSpace.Opens.map_top, Scheme.comp_coeBase, - TopologicalSpace.Opens.map_comp_obj, Scheme.comp_app, CommRingCat.comp_apply] - erw [map_appTop_coord, map_appTop_coord, map_appTop_coord] + · simp lemma map_Spec_map {R S : CommRingCat.{max u v}} (φ : R ⟶ S) : map n (Spec.map φ) = diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean index 231b6e92006e9..189a1bc957349 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean @@ -14,7 +14,7 @@ This file defines the type of points on a Weierstrass curve as an inductive, con at infinity and affine points satisfying a Weierstrass equation with a nonsingular condition. This file also defines the negation and addition operations of the group law for this type, and proves that they respect the Weierstrass equation and the nonsingular condition. The fact that they form an -abelian group is proven in `Mathlib.AlgebraicGeometry.EllipticCurve.Group`. +abelian group is proven in `Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean`. ## Mathematical background @@ -65,7 +65,7 @@ The group law on this set is then uniquely determined by these constructions. * `WeierstrassCurve.Affine.nonsingular_add`: addition preserves the nonsingular condition. * `WeierstrassCurve.Affine.nonsingular_of_Δ_ne_zero`: an affine Weierstrass curve is nonsingular at every point if its discriminant is non-zero. - * `EllipticCurve.Affine.nonsingular`: an affine elliptic curve is nonsingular at every point. + * `WeierstrassCurve.Affine.nonsingular`: an affine elliptic curve is nonsingular at every point. ## Notations @@ -948,21 +948,16 @@ end BaseChange @[deprecated (since := "2024-06-03")] alias baseChange_addY' := baseChange_negAddY @[deprecated (since := "2024-06-03")] alias map_addY' := map_negAddY -end WeierstrassCurve.Affine - /-! ## Elliptic curves -/ -/-- The coercion from an elliptic curve to a Weierstrass curve in affine coordinates. -/ -abbrev EllipticCurve.toAffine {R : Type u} [CommRing R] (E : EllipticCurve R) : - WeierstrassCurve.Affine R := - E.toWeierstrassCurve.toAffine - -namespace EllipticCurve.Affine +section EllipticCurve -variable {R : Type u} [CommRing R] (E : EllipticCurve R) +variable {R : Type u} [CommRing R] (E : WeierstrassCurve R) [E.IsElliptic] lemma nonsingular [Nontrivial R] {x y : R} (h : E.toAffine.Equation x y) : E.toAffine.Nonsingular x y := E.toAffine.nonsingular_of_Δ_ne_zero h <| E.coe_Δ' ▸ E.Δ'.ne_zero -end EllipticCurve.Affine +end EllipticCurve + +end WeierstrassCurve.Affine diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean index 15a2fccfcd2b3..d5026ebed2afd 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Basic.lean @@ -15,75 +15,70 @@ These are defined in terms of the auxiliary sequences for normalised elliptic di ## Mathematical background -Let $W$ be a Weierstrass curve over a commutative ring $R$. The sequence of $n$-division polynomials -$\psi_n \in R[X, Y]$ of $W$ is the normalised EDS with initial values - * $\psi_0 := 0$, - * $\psi_1 := 1$, - * $\psi_2 := 2Y + a_1X + a_3$, - * $\psi_3 := 3X^4 + b_2X^3 + 3b_4X ^ 2 + 3b_6X + b_8$, and - * $\psi_4 := \psi_2 \cdot - (2X^6 + b_2X^5 + 5b_4X^4 + 10b_6X^3 + 10b_8X^2 + (b_2b_8 - b_4b_6)X + (b_4b_8 - b_6^2))$. - -Furthermore, define the associated sequences $\phi_n, \omega_n \in R[X, Y]$ by - * $\phi_n := X\psi_n^2 - \psi_{n + 1} \cdot \psi_{n - 1}$, and - * $\omega_n := (\psi_{2n} / \psi_n - \psi_n \cdot (a_1\phi_n + a_3\psi_n^2)) / 2$. - -Note that $\omega_n$ is always well-defined as a polynomial in $R[X, Y]$. As a start, it can be -shown by induction that $\psi_n$ always divides $\psi_{2n}$ in $R[X, Y]$, so that -$\psi_{2n} / \psi_n$ is always well-defined as a polynomial, while division by 2 is well-defined -when $R$ has characteristic different from 2. In general, it can be shown that 2 always divides the -polynomial $\psi_{2n} / \psi_n - \psi_n \cdot (a_1\phi_n + a_3\psi_n^2)$ in the characteristic zero -universal ring $\mathcal{R}[X, Y] := \mathbb{Z}[A_1, A_2, A_3, A_4, A_6][X, Y]$ of $W$, where the -$A_i$ are indeterminates. Then $\omega_n$ can be equivalently defined as the image of this division -under the associated universal morphism $\mathcal{R}[X, Y] \to R[X, Y]$ mapping $A_i$ to $a_i$. - -Now, in the coordinate ring $R[W]$, note that $\psi_2^2$ is congruent to the polynomial -$\Psi_2^{[2]} := 4X^3 + b_2X^2 + 2b_4X + b_6 \in R[X]$. As such, in $R[W]$, the recurrences -associated to a normalised EDS show that $\psi_n / \psi_2$ are congruent to certain polynomials in -$R[X]$. In particular, define $\tilde{\Psi}_n \in R[X]$ as the auxiliary sequence for a normalised -EDS with extra parameter $(\Psi_2^{[2]})^2$ and initial values - * $\tilde{\Psi}_0 := 0$, - * $\tilde{\Psi}_1 := 1$, - * $\tilde{\Psi}_2 := 1$, - * $\tilde{\Psi}_3 := \psi_3$, and - * $\tilde{\Psi}_4 := \psi_4 / \psi_2$. - -The corresponding normalised EDS $\Psi_n \in R[X, Y]$ is then given by - * $\Psi_n := \tilde{\Psi}_n \cdot \psi_2$ if $n$ is even, and - * $\Psi_n := \tilde{\Psi}_n$ if $n$ is odd. - -Furthermore, define the associated sequences $\Psi_n^{[2]}, \Phi_n \in R[X]$ by - * $\Psi_n^{[2]} := \tilde{\Psi}_n^2 \cdot \Psi_2^{[2]}$ if $n$ is even, - * $\Psi_n^{[2]} := \tilde{\Psi}_n^2$ if $n$ is odd, - * $\Phi_n := X\Psi_n^{[2]} - \tilde{\Psi}_{n + 1} \cdot \tilde{\Psi}_{n - 1}$ if $n$ is even, and - * $\Phi_n := X\Psi_n^{[2]} - \tilde{\Psi}_{n + 1} \cdot \tilde{\Psi}_{n - 1} \cdot \Psi_2^{[2]}$ - if $n$ is odd. - -With these definitions in mind, $\psi_n \in R[X, Y]$ and $\phi_n \in R[X, Y]$ are congruent in -$R[W]$ to $\Psi_n \in R[X, Y]$ and $\Phi_n \in R[X]$ respectively, which are defined in terms of -$\Psi_2^{[2]} \in R[X]$ and $\tilde{\Psi}_n \in R[X]$. +Let `W` be a Weierstrass curve over a commutative ring `R`. The sequence of `n`-division polynomials +`ψₙ ∈ R[X, Y]` of `W` is the normalised EDS with initial values + * `ψ₀ := 0`, + * `ψ₁ := 1`, + * `ψ₂ := 2Y + a₁X + a₃`, + * `ψ₃ := 3X⁴ + b₂X³ + 3b₄X² + 3b₆X + b₈`, and + * `ψ₄ := ψ₂ ⬝ (2X⁶ + b₂X⁵ + 5b₄X⁴ + 10b₆X³ + 10b₈X² + (b₂b₈ - b₄b₆)X + (b₄b₈ - b₆²))`. + +Furthermore, define the associated sequences `φₙ, ωₙ ∈ R[X, Y]` by + * `φₙ := Xψₙ² - ψₙ₊₁ ⬝ ψₙ₋₁`, and + * `ωₙ := (ψ₂ₙ / ψₙ - ψₙ ⬝ (a₁φₙ + a₃ψₙ²)) / 2`. + +Note that `ωₙ` is always well-defined as a polynomial in `R[X, Y]`. As a start, it can be shown by +induction that `ψₙ` always divides `ψ₂ₙ` in `R[X, Y]`, so that `ψ₂ₙ / ψₙ` is always well-defined as +a polynomial, while division by `2` is well-defined when `R` has characteristic different from `2`. +In general, it can be shown that `2` always divides the polynomial `ψ₂ₙ / ψₙ - ψₙ ⬝ (a₁φₙ + a₃ψₙ²)` +in the characteristic `0` universal ring `𝓡[X, Y] := ℤ[A₁, A₂, A₃, A₄, A₆][X, Y]` of `W`, where the +`Aᵢ` are indeterminates. Then `ωₙ` can be equivalently defined as the image of this division under +the associated universal morphism `𝓡[X, Y] → R[X, Y]` mapping `Aᵢ` to `aᵢ`. + +Now, in the coordinate ring `R[W]`, note that `ψ₂²` is congruent to the polynomial +`Ψ₂Sq := 4X³ + b₂X² + 2b₄X + b₆ ∈ R[X]`. As such, the recurrences of a normalised EDS show that +`ψₙ / ψ₂` are congruent to certain polynomials in `R[W]`. In particular, define `preΨₙ ∈ R[X]` as +the auxiliary sequence for a normalised EDS with extra parameter `Ψ₂Sq²` and initial values + * `preΨ₀ := 0`, + * `preΨ₁ := 1`, + * `preΨ₂ := 1`, + * `preΨ₃ := ψ₃`, and + * `preΨ₄ := ψ₄ / ψ₂`. + +The corresponding normalised EDS `Ψₙ ∈ R[X, Y]` is then given by + * `Ψₙ := preΨₙ ⬝ ψ₂` if `n` is even, and + * `Ψₙ := preΨₙ` if `n` is odd. + +Furthermore, define the associated sequences `ΨSqₙ, Φₙ ∈ R[X]` by + * `ΨSqₙ := preΨₙ² ⬝ Ψ₂Sq` if `n` is even, + * `ΨSqₙ := preΨₙ²` if `n` is odd, + * `Φₙ := XΨSqₙ - preΨₙ₊₁ ⬝ preΨₙ₋₁` if `n` is even, and + * `Φₙ := XΨSqₙ - preΨₙ₊₁ ⬝ preΨₙ₋₁ ⬝ Ψ₂Sq` if `n` is odd. + +With these definitions, `ψₙ ∈ R[X, Y]` and `φₙ ∈ R[X, Y]` are congruent in `R[W]` to `Ψₙ ∈ R[X, Y]` +and `Φₙ ∈ R[X]` respectively, which are defined in terms of `Ψ₂Sq ∈ R[X]` and `preΨₙ ∈ R[X]`. ## Main definitions - * `WeierstrassCurve.preΨ`: the univariate polynomials $\tilde{\Psi}_n$. - * `WeierstrassCurve.ΨSq`: the univariate polynomials $\Psi_n^{[2]}$. - * `WeierstrassCurve.Ψ`: the bivariate polynomials $\Psi_n$. - * `WeierstrassCurve.Φ`: the univariate polynomials $\Phi_n$. - * `WeierstrassCurve.ψ`: the bivariate $n$-division polynomials $\psi_n$. - * `WeierstrassCurve.φ`: the bivariate polynomials $\phi_n$. - * TODO: the bivariate polynomials $\omega_n$. + * `WeierstrassCurve.preΨ`: the univariate polynomials `preΨₙ`. + * `WeierstrassCurve.ΨSq`: the univariate polynomials `ΨSqₙ`. + * `WeierstrassCurve.Ψ`: the bivariate polynomials `Ψₙ`. + * `WeierstrassCurve.Φ`: the univariate polynomials `Φₙ`. + * `WeierstrassCurve.ψ`: the bivariate `n`-division polynomials `ψₙ`. + * `WeierstrassCurve.φ`: the bivariate polynomials `φₙ`. + * TODO: the bivariate polynomials `ωₙ`. ## Implementation notes Analogously to `Mathlib.NumberTheory.EllipticDivisibilitySequence`, the bivariate polynomials -$\Psi_n$ are defined in terms of the univariate polynomials $\tilde{\Psi}_n$. This is done partially -to avoid ring division, but more crucially to allow the definition of $\Psi_n^{[2]}$ and $\Phi_n$ as -univariate polynomials without needing to work under the coordinate ring, and to allow the -computation of their leading terms without ambiguity. Furthermore, evaluating these polynomials at a -rational point on $W$ recovers their original definition up to linear combinations of the -Weierstrass equation of $W$, hence also avoiding the need to work in the coordinate ring. +`Ψₙ` are defined in terms of the univariate polynomials `preΨₙ`. This is done partially to avoid +ring division, but more crucially to allow the definition of `ΨSqₙ` and `Φₙ` as univariate +polynomials without needing to work under the coordinate ring, and to allow the computation of their +leading terms without ambiguity. Furthermore, evaluating these polynomials at a rational point on +`W` recovers their original definition up to linear combinations of the Weierstrass equation of `W`, +hence also avoiding the need to work in the coordinate ring. -TODO: implementation notes for the definition of $\omega_n$. +TODO: implementation notes for the definition of `ωₙ`. ## References @@ -114,13 +109,13 @@ variable {R : Type r} {S : Type s} [CommRing R] [CommRing S] (W : WeierstrassCur section Ψ₂Sq -/-! ### The univariate polynomial $\Psi_2^{[2]}$ -/ +/-! ### The univariate polynomial `Ψ₂Sq` -/ -/-- The $2$-division polynomial $\psi_2 = \Psi_2$. -/ +/-- The `2`-division polynomial `ψ₂ = Ψ₂`. -/ noncomputable def ψ₂ : R[X][Y] := W.toAffine.polynomialY -/-- The univariate polynomial $\Psi_2^{[2]}$ congruent to $\psi_2^2$. -/ +/-- The univariate polynomial `Ψ₂Sq` congruent to `ψ₂²`. -/ noncomputable def Ψ₂Sq : R[X] := C 4 * X ^ 3 + C W.b₂ * X ^ 2 + C (2 * W.b₄) * X + C W.b₆ @@ -143,20 +138,20 @@ end Ψ₂Sq section preΨ' -/-! ### The univariate polynomials $\tilde{\Psi}_n$ for $n \in \mathbb{N}$ -/ +/-! ### The univariate polynomials `preΨₙ` for `n ∈ ℕ` -/ -/-- The $3$-division polynomial $\psi_3 = \Psi_3$. -/ +/-- The `3`-division polynomial `ψ₃ = Ψ₃`. -/ noncomputable def Ψ₃ : R[X] := 3 * X ^ 4 + C W.b₂ * X ^ 3 + 3 * C W.b₄ * X ^ 2 + 3 * C W.b₆ * X + C W.b₈ -/-- The univariate polynomial $\tilde{\Psi}_4$, which is auxiliary to the $4$-division polynomial -$\psi_4 = \Psi_4 = \tilde{\Psi}_4\psi_2$. -/ +/-- The univariate polynomial `preΨ₄`, which is auxiliary to the 4-division polynomial +`ψ₄ = Ψ₄ = preΨ₄ψ₂`. -/ noncomputable def preΨ₄ : R[X] := 2 * X ^ 6 + C W.b₂ * X ^ 5 + 5 * C W.b₄ * X ^ 4 + 10 * C W.b₆ * X ^ 3 + 10 * C W.b₈ * X ^ 2 + C (W.b₂ * W.b₈ - W.b₄ * W.b₆) * X + C (W.b₄ * W.b₈ - W.b₆ ^ 2) -/-- The univariate polynomials $\tilde{\Psi}_n$ for $n \in \mathbb{N}$, which are auxiliary to the -bivariate polynomials $\Psi_n$ congruent to the bivariate $n$-division polynomials $\psi_n$. -/ +/-- The univariate polynomials `preΨₙ` for `n ∈ ℕ`, which are auxiliary to the bivariate polynomials +`Ψₙ` congruent to the bivariate `n`-division polynomials `ψₙ`. -/ noncomputable def preΨ' (n : ℕ) : R[X] := preNormEDS' (W.Ψ₂Sq ^ 2) W.Ψ₃ W.preΨ₄ n @@ -180,24 +175,24 @@ lemma preΨ'_three : W.preΨ' 3 = W.Ψ₃ := lemma preΨ'_four : W.preΨ' 4 = W.preΨ₄ := preNormEDS'_four .. -lemma preΨ'_odd (m : ℕ) : W.preΨ' (2 * (m + 2) + 1) = - W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - - W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2) := - preNormEDS'_odd .. - lemma preΨ'_even (m : ℕ) : W.preΨ' (2 * (m + 3)) = W.preΨ' (m + 2) ^ 2 * W.preΨ' (m + 3) * W.preΨ' (m + 5) - W.preΨ' (m + 1) * W.preΨ' (m + 3) * W.preΨ' (m + 4) ^ 2 := preNormEDS'_even .. +lemma preΨ'_odd (m : ℕ) : W.preΨ' (2 * (m + 2) + 1) = + W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - + W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2) := + preNormEDS'_odd .. + end preΨ' section preΨ -/-! ### The univariate polynomials $\tilde{\Psi}_n$ for $n \in \mathbb{Z}$ -/ +/-! ### The univariate polynomials `preΨₙ` for `n ∈ ℤ` -/ -/-- The univariate polynomials $\tilde{\Psi}_n$ for $n \in \mathbb{Z}$, which are auxiliary to the -bivariate polynomials $\Psi_n$ congruent to the bivariate $n$-division polynomials $\psi_n$. -/ +/-- The univariate polynomials `preΨₙ` for `n ∈ ℤ`, which are auxiliary to the bivariate polynomials +`Ψₙ` congruent to the bivariate `n`-division polynomials `ψₙ`. -/ noncomputable def preΨ (n : ℤ) : R[X] := preNormEDS (W.Ψ₂Sq ^ 2) W.Ψ₃ W.preΨ₄ n @@ -225,27 +220,37 @@ lemma preΨ_three : W.preΨ 3 = W.Ψ₃ := lemma preΨ_four : W.preΨ 4 = W.preΨ₄ := preNormEDS_four .. -lemma preΨ_odd (m : ℕ) : W.preΨ (2 * (m + 2) + 1) = - W.preΨ (m + 4) * W.preΨ (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - - W.preΨ (m + 1) * W.preΨ (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2) := - preNormEDS_odd .. - -lemma preΨ_even (m : ℕ) : W.preΨ (2 * (m + 3)) = +lemma preΨ_even_ofNat (m : ℕ) : W.preΨ (2 * (m + 3)) = W.preΨ (m + 2) ^ 2 * W.preΨ (m + 3) * W.preΨ (m + 5) - W.preΨ (m + 1) * W.preΨ (m + 3) * W.preΨ (m + 4) ^ 2 := - preNormEDS_even .. + preNormEDS_even_ofNat .. + +lemma preΨ_odd_ofNat (m : ℕ) : W.preΨ (2 * (m + 2) + 1) = + W.preΨ (m + 4) * W.preΨ (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - + W.preΨ (m + 1) * W.preΨ (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2) := + preNormEDS_odd_ofNat .. @[simp] lemma preΨ_neg (n : ℤ) : W.preΨ (-n) = -W.preΨ n := preNormEDS_neg .. +lemma preΨ_even (m : ℤ) : W.preΨ (2 * m) = + W.preΨ (m - 1) ^ 2 * W.preΨ m * W.preΨ (m + 2) - + W.preΨ (m - 2) * W.preΨ m * W.preΨ (m + 1) ^ 2 := + preNormEDS_even .. + +lemma preΨ_odd (m : ℤ) : W.preΨ (2 * m + 1) = + W.preΨ (m + 2) * W.preΨ m ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - + W.preΨ (m - 1) * W.preΨ (m + 1) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2) := + preNormEDS_odd .. + end preΨ section ΨSq -/-! ### The univariate polynomials $\Psi_n^{[2]}$ -/ +/-! ### The univariate polynomials `ΨSqₙ` -/ -/-- The univariate polynomials $\Psi_n^{[2]}$ congruent to $\psi_n^2$. -/ +/-- The univariate polynomials `ΨSqₙ` congruent to `ψₙ²`. -/ noncomputable def ΨSq (n : ℤ) : R[X] := W.preΨ n ^ 2 * if Even n then W.Ψ₂Sq else 1 @@ -255,45 +260,55 @@ lemma ΨSq_ofNat (n : ℕ) : W.ΨSq n = W.preΨ' n ^ 2 * if Even n then W.Ψ₂S @[simp] lemma ΨSq_zero : W.ΨSq 0 = 0 := by - erw [ΨSq_ofNat, preΨ'_zero, zero_pow two_ne_zero, zero_mul] + rw [← Nat.cast_zero, ΨSq_ofNat, preΨ'_zero, zero_pow two_ne_zero, zero_mul] @[simp] lemma ΨSq_one : W.ΨSq 1 = 1 := by - erw [ΨSq_ofNat, preΨ'_one, one_pow, mul_one] + rw [← Nat.cast_one, ΨSq_ofNat, preΨ'_one, one_pow, one_mul, if_neg Nat.not_even_one] @[simp] lemma ΨSq_two : W.ΨSq 2 = W.Ψ₂Sq := by - erw [ΨSq_ofNat, preΨ'_two, one_pow, one_mul, if_pos even_two] + rw [← Nat.cast_two, ΨSq_ofNat, preΨ'_two, one_pow, one_mul, if_pos even_two] @[simp] lemma ΨSq_three : W.ΨSq 3 = W.Ψ₃ ^ 2 := by - erw [ΨSq_ofNat, preΨ'_three, mul_one] + rw [← Nat.cast_three, ΨSq_ofNat, preΨ'_three, if_neg <| by decide, mul_one] @[simp] lemma ΨSq_four : W.ΨSq 4 = W.preΨ₄ ^ 2 * W.Ψ₂Sq := by - erw [ΨSq_ofNat, preΨ'_four, if_pos <| by decide] - -lemma ΨSq_odd (m : ℕ) : W.ΨSq (2 * (m + 2) + 1) = - (W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - - W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2)) ^ 2 := by - erw [ΨSq_ofNat, preΨ'_odd, if_neg (m + 2).not_even_two_mul_add_one, mul_one] + rw [← Nat.cast_four, ΨSq_ofNat, preΨ'_four, if_pos <| by decide] -lemma ΨSq_even (m : ℕ) : W.ΨSq (2 * (m + 3)) = +lemma ΨSq_even_ofNat (m : ℕ) : W.ΨSq (2 * (m + 3)) = (W.preΨ' (m + 2) ^ 2 * W.preΨ' (m + 3) * W.preΨ' (m + 5) - W.preΨ' (m + 1) * W.preΨ' (m + 3) * W.preΨ' (m + 4) ^ 2) ^ 2 * W.Ψ₂Sq := by - erw [ΨSq_ofNat, preΨ'_even, if_pos <| even_two_mul _] + rw_mod_cast [ΨSq_ofNat, preΨ'_even, if_pos <| even_two_mul _] + +lemma ΨSq_odd_ofNat (m : ℕ) : W.ΨSq (2 * (m + 2) + 1) = + (W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - + W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2)) ^ 2 := by + rw_mod_cast [ΨSq_ofNat, preΨ'_odd, if_neg (m + 2).not_even_two_mul_add_one, mul_one] @[simp] lemma ΨSq_neg (n : ℤ) : W.ΨSq (-n) = W.ΨSq n := by simp only [ΨSq, preΨ_neg, neg_sq, even_neg] +lemma ΨSq_even (m : ℤ) : W.ΨSq (2 * m) = + (W.preΨ (m - 1) ^ 2 * W.preΨ m * W.preΨ (m + 2) - + W.preΨ (m - 2) * W.preΨ m * W.preΨ (m + 1) ^ 2) ^ 2 * W.Ψ₂Sq := by + rw [ΨSq, preΨ_even, if_pos <| even_two_mul _] + +lemma ΨSq_odd (m : ℤ) : W.ΨSq (2 * m + 1) = + (W.preΨ (m + 2) * W.preΨ m ^ 3 * (if Even m then W.Ψ₂Sq ^ 2 else 1) - + W.preΨ (m - 1) * W.preΨ (m + 1) ^ 3 * (if Even m then 1 else W.Ψ₂Sq ^ 2)) ^ 2 := by + rw [ΨSq, preΨ_odd, if_neg m.not_even_two_mul_add_one, mul_one] + end ΨSq section Ψ -/-! ### The bivariate polynomials $\Psi_n$ -/ +/-! ### The bivariate polynomials `Ψₙ` -/ -/-- The bivariate polynomials $\Psi_n$ congruent to the $n$-division polynomials $\psi_n$. -/ +/-- The bivariate polynomials `Ψₙ` congruent to the `n`-division polynomials `ψₙ`. -/ protected noncomputable def Ψ (n : ℤ) : R[X][Y] := C (W.preΨ n) * if Even n then W.ψ₂ else 1 @@ -305,43 +320,60 @@ lemma Ψ_ofNat (n : ℕ) : W.Ψ n = C (W.preΨ' n) * if Even n then W.ψ₂ else @[simp] lemma Ψ_zero : W.Ψ 0 = 0 := by - erw [Ψ_ofNat, preΨ'_zero, C_0, zero_mul] + rw [← Nat.cast_zero, Ψ_ofNat, preΨ'_zero, C_0, zero_mul] @[simp] lemma Ψ_one : W.Ψ 1 = 1 := by - erw [Ψ_ofNat, preΨ'_one, C_1, mul_one] + rw [← Nat.cast_one, Ψ_ofNat, preΨ'_one, C_1, if_neg Nat.not_even_one, mul_one] @[simp] lemma Ψ_two : W.Ψ 2 = W.ψ₂ := by - erw [Ψ_ofNat, preΨ'_two, one_mul, if_pos even_two] + rw [← Nat.cast_two, Ψ_ofNat, preΨ'_two, C_1, one_mul, if_pos even_two] @[simp] lemma Ψ_three : W.Ψ 3 = C W.Ψ₃ := by - erw [Ψ_ofNat, preΨ'_three, mul_one] + rw [← Nat.cast_three, Ψ_ofNat, preΨ'_three, if_neg <| by decide, mul_one] @[simp] lemma Ψ_four : W.Ψ 4 = C W.preΨ₄ * W.ψ₂ := by - erw [Ψ_ofNat, preΨ'_four, if_pos <| by decide] + rw [← Nat.cast_four, Ψ_ofNat, preΨ'_four, if_pos <| by decide] -lemma Ψ_odd (m : ℕ) : W.Ψ (2 * (m + 2) + 1) = - W.Ψ (m + 4) * W.Ψ (m + 2) ^ 3 - W.Ψ (m + 1) * W.Ψ (m + 3) ^ 3 + - W.toAffine.polynomial * (16 * W.toAffine.polynomial - 8 * W.ψ₂ ^ 2) * C - (if Even m then W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 - else -W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3) := by - repeat erw [Ψ_ofNat] - simp_rw [preΨ'_odd, if_neg (m + 2).not_even_two_mul_add_one, Nat.even_add_one, ite_not] - split_ifs <;> C_simp <;> rw [C_Ψ₂Sq] <;> ring1 - -lemma Ψ_even (m : ℕ) : W.Ψ (2 * (m + 3)) * W.ψ₂ = +lemma Ψ_even_ofNat (m : ℕ) : W.Ψ (2 * (m + 3)) * W.ψ₂ = W.Ψ (m + 2) ^ 2 * W.Ψ (m + 3) * W.Ψ (m + 5) - W.Ψ (m + 1) * W.Ψ (m + 3) * W.Ψ (m + 4) ^ 2 := by - repeat erw [Ψ_ofNat] + repeat rw_mod_cast [Ψ_ofNat] simp_rw [preΨ'_even, if_pos <| even_two_mul _, Nat.even_add_one, ite_not] split_ifs <;> C_simp <;> ring1 +lemma Ψ_odd_ofNat (m : ℕ) : W.Ψ (2 * (m + 2) + 1) = + W.Ψ (m + 4) * W.Ψ (m + 2) ^ 3 - W.Ψ (m + 1) * W.Ψ (m + 3) ^ 3 + + W.toAffine.polynomial * (16 * W.toAffine.polynomial - 8 * W.ψ₂ ^ 2) * + C (if Even m then W.preΨ' (m + 4) * W.preΨ' (m + 2) ^ 3 + else -W.preΨ' (m + 1) * W.preΨ' (m + 3) ^ 3) := by + repeat rw_mod_cast [Ψ_ofNat] + simp_rw [preΨ'_odd, if_neg (m + 2).not_even_two_mul_add_one, Nat.even_add_one, ite_not] + split_ifs <;> C_simp <;> rw [C_Ψ₂Sq] <;> ring1 + @[simp] lemma Ψ_neg (n : ℤ) : W.Ψ (-n) = -W.Ψ n := by simp only [Ψ, preΨ_neg, C_neg, neg_mul (α := R[X][Y]), even_neg] +lemma Ψ_even (m : ℤ) : W.Ψ (2 * m) * W.ψ₂ = + W.Ψ (m - 1) ^ 2 * W.Ψ m * W.Ψ (m + 2) - W.Ψ (m - 2) * W.Ψ m * W.Ψ (m + 1) ^ 2 := by + repeat rw [Ψ] + simp_rw [preΨ_even, if_pos <| even_two_mul _, Int.even_add_one, show m + 2 = m + 1 + 1 by ring1, + Int.even_add_one, show m - 2 = m - 1 - 1 by ring1, Int.even_sub_one, ite_not] + split_ifs <;> C_simp <;> ring1 + +lemma Ψ_odd (m : ℤ) : W.Ψ (2 * m + 1) = + W.Ψ (m + 2) * W.Ψ m ^ 3 - W.Ψ (m - 1) * W.Ψ (m + 1) ^ 3 + + W.toAffine.polynomial * (16 * W.toAffine.polynomial - 8 * W.ψ₂ ^ 2) * + C (if Even m then W.preΨ (m + 2) * W.preΨ m ^ 3 + else -W.preΨ (m - 1) * W.preΨ (m + 1) ^ 3) := by + repeat rw [Ψ] + simp_rw [preΨ_odd, if_neg m.not_even_two_mul_add_one, show m + 2 = m + 1 + 1 by ring1, + Int.even_add_one, Int.even_sub_one, ite_not] + split_ifs <;> C_simp <;> rw [C_Ψ₂Sq] <;> ring1 + lemma Affine.CoordinateRing.mk_Ψ_sq (n : ℤ) : mk W (W.Ψ n) ^ 2 = mk W (C <| W.ΨSq n) := by simp only [Ψ, ΨSq, map_one, map_mul, map_pow, one_pow, mul_pow, ite_pow, apply_ite C, apply_ite <| mk W, mk_ψ₂_sq] @@ -350,9 +382,9 @@ end Ψ section Φ -/-! ### The univariate polynomials $\Phi_n$ -/ +/-! ### The univariate polynomials `Φₙ` -/ -/-- The univariate polynomials $\Phi_n$ congruent to $\phi_n$. -/ +/-- The univariate polynomials `Φₙ` congruent to `φₙ`. -/ protected noncomputable def Φ (n : ℤ) : R[X] := X * W.ΨSq n - W.preΨ (n + 1) * W.preΨ (n - 1) * if Even n then 1 else W.Ψ₂Sq @@ -362,7 +394,8 @@ open WeierstrassCurve (Φ) lemma Φ_ofNat (n : ℕ) : W.Φ (n + 1) = X * W.preΨ' (n + 1) ^ 2 * (if Even n then 1 else W.Ψ₂Sq) - W.preΨ' (n + 2) * W.preΨ' n * (if Even n then W.Ψ₂Sq else 1) := by - erw [Φ, ΨSq_ofNat, ← mul_assoc, preΨ_ofNat, add_sub_cancel_right, preΨ_ofNat] + rw [Φ, ← Nat.cast_one, ← Nat.cast_add, ΨSq_ofNat, ← mul_assoc, ← Nat.cast_add, preΨ_ofNat, + Nat.cast_add, add_sub_cancel_right, preΨ_ofNat, ← Nat.cast_add] simp only [Nat.even_add_one, Int.even_add_one, Int.even_coe_nat, ite_not] @[simp] @@ -372,22 +405,26 @@ lemma Φ_zero : W.Φ 0 = 1 := by @[simp] lemma Φ_one : W.Φ 1 = X := by - erw [Φ_ofNat, preΨ'_one, one_pow, mul_one, mul_one, preΨ'_zero, mul_zero, zero_mul, sub_zero] + rw [show 1 = ((0 : ℕ) + 1 : ℤ) by rfl, Φ_ofNat, preΨ'_one, one_pow, mul_one, if_pos even_zero, + mul_one, preΨ'_zero, mul_zero, zero_mul, sub_zero] @[simp] lemma Φ_two : W.Φ 2 = X ^ 4 - C W.b₄ * X ^ 2 - C (2 * W.b₆) * X - C W.b₈ := by - erw [Φ_ofNat, preΨ'_two, if_neg Nat.not_even_one, Ψ₂Sq, preΨ'_three, preΨ'_one, mul_one, Ψ₃] + rw [show 2 = ((1 : ℕ) + 1 : ℤ) by rfl, Φ_ofNat, preΨ'_two, if_neg Nat.not_even_one, Ψ₂Sq, + preΨ'_three, preΨ'_one, if_neg Nat.not_even_one, Ψ₃] C_simp ring1 @[simp] lemma Φ_three : W.Φ 3 = X * W.Ψ₃ ^ 2 - W.preΨ₄ * W.Ψ₂Sq := by - erw [Φ_ofNat, preΨ'_three, mul_one, preΨ'_four, preΨ'_two, mul_one, if_pos even_two] + rw [show 3 = ((2 : ℕ) + 1 : ℤ) by rfl, Φ_ofNat, preΨ'_three, if_pos <| by decide, mul_one, + preΨ'_four, preΨ'_two, mul_one, if_pos even_two] @[simp] lemma Φ_four : W.Φ 4 = X * W.preΨ₄ ^ 2 * W.Ψ₂Sq - W.Ψ₃ * (W.preΨ₄ * W.Ψ₂Sq ^ 2 - W.Ψ₃ ^ 3) := by - erw [Φ_ofNat, preΨ'_four, if_neg <| by decide, show 3 + 2 = 2 * 2 + 1 by rfl, preΨ'_odd, - preΨ'_four, preΨ'_two, if_pos even_zero, preΨ'_one, preΨ'_three, if_pos even_zero] + rw [show 4 = ((3 : ℕ) + 1 : ℤ) by rfl, Φ_ofNat, preΨ'_four, if_neg <| by decide, + show 3 + 2 = 2 * 2 + 1 by rfl, preΨ'_odd, preΨ'_four, preΨ'_two, if_pos even_zero, preΨ'_one, + preΨ'_three, if_pos even_zero, if_neg <| by decide] ring1 @[simp] @@ -399,9 +436,9 @@ end Φ section ψ -/-! ### The bivariate polynomials $\psi_n$ -/ +/-! ### The bivariate polynomials `ψₙ` -/ -/-- The bivariate $n$-division polynomials $\psi_n$. -/ +/-- The bivariate `n`-division polynomials `ψₙ`. -/ protected noncomputable def ψ (n : ℤ) : R[X][Y] := normEDS W.ψ₂ (C W.Ψ₃) (C W.preΨ₄) n @@ -427,18 +464,26 @@ lemma ψ_three : W.ψ 3 = C W.Ψ₃ := lemma ψ_four : W.ψ 4 = C W.preΨ₄ * W.ψ₂ := normEDS_four .. -lemma ψ_odd (m : ℕ) : W.ψ (2 * (m + 2) + 1) = - W.ψ (m + 4) * W.ψ (m + 2) ^ 3 - W.ψ (m + 1) * W.ψ (m + 3) ^ 3 := - normEDS_odd .. - -lemma ψ_even (m : ℕ) : W.ψ (2 * (m + 3)) * W.ψ₂ = +lemma ψ_even_ofNat (m : ℕ) : W.ψ (2 * (m + 3)) * W.ψ₂ = W.ψ (m + 2) ^ 2 * W.ψ (m + 3) * W.ψ (m + 5) - W.ψ (m + 1) * W.ψ (m + 3) * W.ψ (m + 4) ^ 2 := - normEDS_even .. + normEDS_even_ofNat .. + +lemma ψ_odd_ofNat (m : ℕ) : W.ψ (2 * (m + 2) + 1) = + W.ψ (m + 4) * W.ψ (m + 2) ^ 3 - W.ψ (m + 1) * W.ψ (m + 3) ^ 3 := + normEDS_odd_ofNat .. @[simp] lemma ψ_neg (n : ℤ) : W.ψ (-n) = -W.ψ n := normEDS_neg .. +lemma ψ_even (m : ℤ) : W.ψ (2 * m) * W.ψ₂ = + W.ψ (m - 1) ^ 2 * W.ψ m * W.ψ (m + 2) - W.ψ (m - 2) * W.ψ m * W.ψ (m + 1) ^ 2 := + normEDS_even .. + +lemma ψ_odd (m : ℤ) : W.ψ (2 * m + 1) = + W.ψ (m + 2) * W.ψ m ^ 3 - W.ψ (m - 1) * W.ψ (m + 1) ^ 3 := + normEDS_odd .. + lemma Affine.CoordinateRing.mk_ψ (n : ℤ) : mk W (W.ψ n) = mk W (W.Ψ n) := by simp only [ψ, normEDS, Ψ, preΨ, map_mul, map_pow, map_preNormEDS, ← mk_ψ₂_sq, ← pow_mul] @@ -446,9 +491,9 @@ end ψ section φ -/-! ### The bivariate polynomials $\phi_n$ -/ +/-! ### The bivariate polynomials `φₙ` -/ -/-- The bivariate polynomials $\phi_n$. -/ +/-- The bivariate polynomials `φₙ`. -/ protected noncomputable def φ (n : ℤ) : R[X][Y] := C X * W.ψ n ^ 2 - W.ψ (n + 1) * W.ψ (n - 1) @@ -456,25 +501,28 @@ open WeierstrassCurve (Ψ Φ φ) @[simp] lemma φ_zero : W.φ 0 = 1 := by - erw [φ, ψ_zero, zero_pow two_ne_zero, mul_zero, zero_sub, ψ_one, one_mul, - zero_sub, ψ_neg, neg_neg, ψ_one] + rw [φ, ψ_zero, zero_pow two_ne_zero, mul_zero, zero_sub, zero_add, ψ_one, one_mul, zero_sub, + ψ_neg, neg_neg, ψ_one] @[simp] lemma φ_one : W.φ 1 = C X := by - erw [φ, ψ_one, one_pow, mul_one, ψ_zero, mul_zero, sub_zero] + rw [φ, ψ_one, one_pow, mul_one, sub_self, ψ_zero, mul_zero, sub_zero] @[simp] lemma φ_two : W.φ 2 = C X * W.ψ₂ ^ 2 - C W.Ψ₃ := by - erw [φ, ψ_two, ψ_three, ψ_one, mul_one] + rw [φ, ψ_two, two_add_one_eq_three, ψ_three, show (2 - 1 : ℤ) = 1 by rfl, ψ_one, mul_one] @[simp] lemma φ_three : W.φ 3 = C X * C W.Ψ₃ ^ 2 - C W.preΨ₄ * W.ψ₂ ^ 2 := by - erw [φ, ψ_three, ψ_four, mul_assoc, ψ_two, ← sq] + rw [φ, ψ_three, three_add_one_eq_four, ψ_four, mul_assoc, show (3 - 1 : ℤ) = 2 by rfl, ψ_two, + ← sq] @[simp] lemma φ_four : W.φ 4 = C X * C W.preΨ₄ ^ 2 * W.ψ₂ ^ 2 - C W.preΨ₄ * W.ψ₂ ^ 4 * C W.Ψ₃ + C W.Ψ₃ ^ 4 := by - erw [φ, ψ_four, show (4 + 1 : ℤ) = 2 * 2 + 1 by rfl, ψ_odd, ψ_four, ψ_two, ψ_one, ψ_three] + rw [φ, ψ_four, show (4 + 1 : ℤ) = 2 * 2 + 1 by rfl, ψ_odd, two_add_two_eq_four, ψ_four, + show (2 - 1 : ℤ) = 1 by rfl, ψ_two, ψ_one, two_add_one_eq_three, show (4 - 1 : ℤ) = 3 by rfl, + ψ_three] ring1 @[simp] diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Degree.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Degree.lean index e8193f45e38bd..c92f4e2898103 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Degree.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/DivisionPolynomial/Degree.lean @@ -14,29 +14,29 @@ Weierstrass curves defined in `Mathlib.AlgebraicGeometry.EllipticCurve.DivisionP ## Mathematical background -Let $W$ be a Weierstrass curve over a commutative ring $R$. By strong induction, - * $\tilde{\Psi}_n = \tfrac{n}{2}X^{\tfrac{n^2 - 4}{2}} + \dots$ if $n$ is even, - * $\tilde{\Psi}_n = nX^{\tfrac{n^2 - 1}{2}} + \dots$ if $n$ is odd, - * $\Psi_n^{[2]} = n^2X^{n^2 - 1} + \dots$, and - * $\Phi_n = X^{n^2} + \dots$. +Let `W` be a Weierstrass curve over a commutative ring `R`. By strong induction, + * `preΨₙ` has leading coefficient `n / 2` and degree `(n² - 4) / 2` if `n` is even, + * `preΨₙ` has leading coefficient `n` and degree `(n² - 1) / 2` if `n` is odd, + * `ΨSqₙ` has leading coefficient `n²` and degree `n² - 1`, and + * `Φₙ` has leading coefficient `1` and degree `n²`. -In particular, when $R$ is an integral domain of characteristic different from $n$, the univariate -polynomials $\tilde{\Psi}_n$, $\Psi_n^{[2]}$, and $\Phi_n$ all have their expected leading terms. +In particular, when `R` is an integral domain of characteristic different from `n`, the univariate +polynomials `preΨₙ`, `ΨSqₙ`, and `Φₙ` all have their expected leading terms. ## Main statements - * `WeierstrassCurve.natDegree_preΨ_le`: the expected degree of $\tilde{\Psi}_n$. - * `WeierstrassCurve.coeff_preΨ`: the expected leading coefficient of $\tilde{\Psi}_n$. - * `WeierstrassCurve.natDegree_preΨ`: the degree of $\tilde{\Psi}_n$ when $n \ne 0$. - * `WeierstrassCurve.leadingCoeff_preΨ`: the leading coefficient of $\tilde{\Psi}_n$ when $n \ne 0$. - * `WeierstrassCurve.natDegree_ΨSq_le`: the expected degree of $\Psi_n^{[2]}$. - * `WeierstrassCurve.coeff_ΨSq`: the expected leading coefficient of $\Psi_n^{[2]}$. - * `WeierstrassCurve.natDegree_ΨSq`: the degree of $\Psi_n^{[2]}$ when $n \ne 0$. - * `WeierstrassCurve.leadingCoeff_ΨSq`: the leading coefficient of $\Psi_n^{[2]}$ when $n \ne 0$. - * `WeierstrassCurve.natDegree_Φ_le`: the expected degree of $\Phi_n$. - * `WeierstrassCurve.coeff_Φ`: the expected leading coefficient of $\Phi_n$. - * `WeierstrassCurve.natDegree_Φ`: the degree of $\Phi_n$ when $n \ne 0$. - * `WeierstrassCurve.leadingCoeff_Φ`: the leading coefficient of $\Phi_n$ when $n \ne 0$. + * `WeierstrassCurve.natDegree_preΨ_le`: the degree bound `d` of `preΨₙ`. + * `WeierstrassCurve.coeff_preΨ`: the `d`-th coefficient of `preΨₙ`. + * `WeierstrassCurve.natDegree_preΨ`: the degree of `preΨₙ` when `n ≠ 0`. + * `WeierstrassCurve.leadingCoeff_preΨ`: the leading coefficient of `preΨₙ` when `n ≠ 0`. + * `WeierstrassCurve.natDegree_ΨSq_le`: the degree bound `d` of `ΨSqₙ`. + * `WeierstrassCurve.coeff_ΨSq`: the `d`-th coefficient of `ΨSqₙ`. + * `WeierstrassCurve.natDegree_ΨSq`: the degree of `ΨSqₙ` when `n ≠ 0`. + * `WeierstrassCurve.leadingCoeff_ΨSq`: the leading coefficient of `ΨSqₙ` when `n ≠ 0`. + * `WeierstrassCurve.natDegree_Φ_le`: the degree bound `d` of `Φₙ`. + * `WeierstrassCurve.coeff_Φ`: the `d`-th coefficient of `Φₙ`. + * `WeierstrassCurve.natDegree_Φ`: the degree of `Φₙ` when `n ≠ 0`. + * `WeierstrassCurve.leadingCoeff_Φ`: the leading coefficient of `Φₙ` when `n ≠ 0`. ## References @@ -249,7 +249,7 @@ lemma natDegree_preΨ' {n : ℕ} (h : (n : R) ≠ 0) : natDegree_eq_of_le_of_coeff_ne_zero (W.natDegree_preΨ'_le n) <| W.coeff_preΨ'_ne_zero h lemma natDegree_preΨ'_pos {n : ℕ} (hn : 2 < n) (h : (n : R) ≠ 0) : 0 < (W.preΨ' n).natDegree := by - rw [W.natDegree_preΨ' h, Nat.div_pos_iff two_ne_zero] + simp only [W.natDegree_preΨ' h, Nat.div_pos_iff, zero_lt_two, true_and] split_ifs <;> exact Nat.AtLeastTwo.prop.trans <| Nat.sub_le_sub_right (Nat.pow_le_pow_of_le_left hn 2) _ @@ -271,16 +271,16 @@ lemma natDegree_preΨ_le (n : ℤ) : (W.preΨ n).natDegree ≤ (n.natAbs ^ 2 - if Even n then 4 else 1) / 2 := by induction n using Int.negInduction with | nat n => exact_mod_cast W.preΨ_ofNat n ▸ W.natDegree_preΨ'_le n - | neg => simpa only [preΨ_neg, natDegree_neg, Int.natAbs_neg, even_neg] + | neg ih => simp only [preΨ_neg, natDegree_neg, Int.natAbs_neg, even_neg, ih] @[simp] lemma coeff_preΨ (n : ℤ) : (W.preΨ n).coeff ((n.natAbs ^ 2 - if Even n then 4 else 1) / 2) = if Even n then n / 2 else n := by induction n using Int.negInduction with | nat n => exact_mod_cast W.preΨ_ofNat n ▸ W.coeff_preΨ' n - | neg n ih => + | neg ih n => simp only [preΨ_neg, coeff_neg, Int.natAbs_neg, even_neg] - rcases n.even_or_odd' with ⟨n, rfl | rfl⟩ <;> + rcases ih n, n.even_or_odd' with ⟨ih, ⟨n, rfl | rfl⟩⟩ <;> push_cast [even_two_mul, Int.not_even_two_mul_add_one, Int.neg_ediv_of_dvd ⟨n, rfl⟩] at * <;> rw [ih] @@ -289,8 +289,8 @@ lemma coeff_preΨ_ne_zero {n : ℤ} (h : (n : R) ≠ 0) : induction n using Int.negInduction with | nat n => simpa only [preΨ_ofNat, Int.even_coe_nat] using W.coeff_preΨ'_ne_zero <| by exact_mod_cast h - | neg n ih => simpa only [preΨ_neg, coeff_neg, neg_ne_zero, Int.natAbs_neg, even_neg] - using ih <| neg_ne_zero.mp <| by exact_mod_cast h + | neg ih n => simpa only [preΨ_neg, coeff_neg, neg_ne_zero, Int.natAbs_neg, even_neg] + using ih n <| neg_ne_zero.mp <| by exact_mod_cast h @[simp] lemma natDegree_preΨ {n : ℤ} (h : (n : R) ≠ 0) : @@ -301,8 +301,8 @@ lemma natDegree_preΨ_pos {n : ℤ} (hn : 2 < n.natAbs) (h : (n : R) ≠ 0) : 0 < (W.preΨ n).natDegree := by induction n using Int.negInduction with | nat n => simpa only [preΨ_ofNat] using W.natDegree_preΨ'_pos hn <| by exact_mod_cast h - | neg n ih => simpa only [preΨ_neg, natDegree_neg] - using ih (by rwa [← Int.natAbs_neg]) <| neg_ne_zero.mp <| by exact_mod_cast h + | neg ih n => simpa only [preΨ_neg, natDegree_neg] + using ih n (by rwa [← Int.natAbs_neg]) <| neg_ne_zero.mp <| by exact_mod_cast h @[simp] lemma leadingCoeff_preΨ {n : ℤ} (h : (n : R) ≠ 0) : @@ -312,7 +312,8 @@ lemma leadingCoeff_preΨ {n : ℤ} (h : (n : R) ≠ 0) : lemma preΨ_ne_zero [Nontrivial R] {n : ℤ} (h : (n : R) ≠ 0) : W.preΨ n ≠ 0 := by induction n using Int.negInduction with | nat n => simpa only [preΨ_ofNat] using W.preΨ'_ne_zero <| by exact_mod_cast h - | neg n ih => simpa only [preΨ_neg, neg_ne_zero] using ih <| neg_ne_zero.mp <| by exact_mod_cast h + | neg ih n => simpa only [preΨ_neg, neg_ne_zero] + using ih n <| neg_ne_zero.mp <| by exact_mod_cast h end preΨ @@ -327,14 +328,14 @@ private lemma natDegree_coeff_ΨSq_ofNat (n : ℕ) : have hd : (n + 1) ^ 2 - 1 = 2 * expDegree (n + 1) + if Even (n + 1) then 3 else 0 := by push_cast [← @Nat.cast_inj ℤ, add_sq, expDegree_cast (by omega : n + 1 ≠ 0)] split_ifs <;> ring1 - have hc : (n + 1) ^ 2 = expCoeff (n + 1) ^ 2 * if Even (n + 1) then 4 else 1 := by + have hc : (n + 1 : ℕ) ^ 2 = expCoeff (n + 1) ^ 2 * if Even (n + 1) then 4 else 1 := by push_cast [← @Int.cast_inj ℚ, expCoeff_cast] split_ifs <;> ring1 rw [ΨSq_ofNat, hd] constructor · refine natDegree_mul_le_of_le (dp h.1) ?_ split_ifs <;> simp only [apply_ite natDegree, natDegree_one.le, W.natDegree_Ψ₂Sq_le] - · erw [coeff_mul_of_natDegree_le (dp h.1), coeff_pow_of_natDegree_le h.1, h.2, apply_ite₂ coeff, + · rw [coeff_mul_of_natDegree_le (dp h.1), coeff_pow_of_natDegree_le h.1, h.2, apply_ite₂ coeff, coeff_Ψ₂Sq, coeff_one_zero, hc] · norm_cast split_ifs <;> simp only [apply_ite natDegree, natDegree_one.le, W.natDegree_Ψ₂Sq_le] @@ -342,13 +343,13 @@ private lemma natDegree_coeff_ΨSq_ofNat (n : ℕ) : lemma natDegree_ΨSq_le (n : ℤ) : (W.ΨSq n).natDegree ≤ n.natAbs ^ 2 - 1 := by induction n using Int.negInduction with | nat n => exact (W.natDegree_coeff_ΨSq_ofNat n).left - | neg => rwa [ΨSq_neg, Int.natAbs_neg] + | neg ih => simp only [ΨSq_neg, Int.natAbs_neg, ih] @[simp] lemma coeff_ΨSq (n : ℤ) : (W.ΨSq n).coeff (n.natAbs ^ 2 - 1) = n ^ 2 := by induction n using Int.negInduction with | nat n => exact_mod_cast (W.natDegree_coeff_ΨSq_ofNat n).right - | neg => rwa [ΨSq_neg, Int.natAbs_neg, ← Int.cast_pow, neg_sq, Int.cast_pow] + | neg ih => simp_rw [ΨSq_neg, Int.natAbs_neg, ← Int.cast_pow, neg_sq, Int.cast_pow, ih] lemma coeff_ΨSq_ne_zero [NoZeroDivisors R] {n : ℤ} (h : (n : R) ≠ 0) : (W.ΨSq n).coeff (n.natAbs ^ 2 - 1) ≠ 0 := by @@ -404,7 +405,7 @@ private lemma natDegree_coeff_Φ_ofNat (n : ℕ) : expCoeff (n + 3) * expCoeff (n + 1) * (if Even (n + 1) then 4 else 1) := by push_cast [← @Int.cast_inj ℚ, expCoeff_cast, Nat.even_add_one, ite_not] split_ifs <;> ring1 - erw [Φ_ofNat] + rw [Nat.cast_add, Nat.cast_one, Φ_ofNat] constructor · nth_rw 1 [← max_self <| (_ + _) ^ 2, hd, hd'] refine natDegree_sub_le_of_le (dm (dm natDegree_X_le (dp h.1)) ?_) (dm (dm h.1 h.1) ?_) @@ -419,13 +420,13 @@ private lemma natDegree_coeff_Φ_ofNat (n : ℕ) : lemma natDegree_Φ_le (n : ℤ) : (W.Φ n).natDegree ≤ n.natAbs ^ 2 := by induction n using Int.negInduction with | nat n => exact (W.natDegree_coeff_Φ_ofNat n).left - | neg => rwa [Φ_neg, Int.natAbs_neg] + | neg ih => simp only [Φ_neg, Int.natAbs_neg, ih] @[simp] lemma coeff_Φ (n : ℤ) : (W.Φ n).coeff (n.natAbs ^ 2) = 1 := by induction n using Int.negInduction with | nat n => exact (W.natDegree_coeff_Φ_ofNat n).right - | neg => rwa [Φ_neg, Int.natAbs_neg] + | neg ih => simp only [Φ_neg, Int.natAbs_neg, ih] lemma coeff_Φ_ne_zero [Nontrivial R] (n : ℤ) : (W.Φ n).coeff (n.natAbs ^ 2) ≠ 0 := W.coeff_Φ n ▸ one_ne_zero diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean index c01a58c13679a..faa80b6bd843f 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Group.lean @@ -12,8 +12,8 @@ import Mathlib.RingTheory.Polynomial.UniqueFactorization # Group law on Weierstrass curves This file proves that the nonsingular rational points on a Weierstrass curve forms an abelian group -under the geometric group law defined in `Mathlib.AlgebraicGeometry.EllipticCurve.Affine` and in -`Mathlib.AlgebraicGeometry.EllipticCurve.Jacobian`. +under the geometric group law defined in `Mathlib/AlgebraicGeometry/EllipticCurve/Affine.lean` and +in `Mathlib/AlgebraicGeometry/EllipticCurve/Jacobian.lean`. ## Mathematical background @@ -326,13 +326,13 @@ lemma XYIdeal_neg_mul {x y : F} (h : W.Nonsingular x y) : refine ⟨C <| C W_X⁻¹ * -(X + C (2 * x + W.a₂)), C <| C <| W_X⁻¹ * W.a₁, 0, C <| C <| W_X⁻¹ * -1, ?_⟩ rw [← mul_right_inj' <| C_ne_zero.mpr <| C_ne_zero.mpr hx] - simp only [mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hx] + simp only [W_X, mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hx] C_simp ring1 · let W_Y := 2 * y + W.a₁ * x + W.a₃ refine ⟨0, C <| C W_Y⁻¹, C <| C <| W_Y⁻¹ * -1, 0, ?_⟩ rw [negY, ← mul_right_inj' <| C_ne_zero.mpr <| C_ne_zero.mpr hy] - simp only [mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hy] + simp only [W_Y, mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hy] C_simp ring1 @@ -374,7 +374,7 @@ lemma XYIdeal_mul_XYIdeal {x₁ x₂ y₁ y₂ : F} (h₁ : W.Equation x₁ y₁ 0, C (C y⁻¹) * (Y - W.negPolynomial), ?_⟩, by rw [map_add, map_one, _root_.map_mul <| mk W, AdjoinRoot.mk_self, mul_zero, add_zero]⟩ rw [polynomial, negPolynomial, ← mul_right_inj' <| C_ne_zero.mpr <| C_ne_zero.mpr hxy] - simp only [mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hxy] + simp only [y, mul_add, ← mul_assoc, ← C_mul, mul_inv_cancel₀ hxy] linear_combination (norm := (rw [b₂, b₄, negY]; C_simp; ring1)) -4 * congr_arg C (congr_arg C <| (equation_iff ..).mp h₁) · replace hx := sub_ne_zero_of_ne hx @@ -582,14 +582,14 @@ noncomputable instance : AddCommGroup W.Point where end WeierstrassCurve.Jacobian.Point -namespace EllipticCurve.Affine.Point +namespace WeierstrassCurve.Affine.Point /-! ## Elliptic curves in affine coordinates -/ -variable {R : Type} [Nontrivial R] [CommRing R] (E : EllipticCurve R) +variable {R : Type*} [Nontrivial R] [CommRing R] (E : WeierstrassCurve R) [E.IsElliptic] /-- An affine point on an elliptic curve `E` over `R`. -/ def mk {x y : R} (h : E.toAffine.Equation x y) : E.toAffine.Point := WeierstrassCurve.Affine.Point.some <| nonsingular E h -end EllipticCurve.Affine.Point +end WeierstrassCurve.Affine.Point diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/J.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/IsomOfJ.lean similarity index 91% rename from Mathlib/AlgebraicGeometry/EllipticCurve/J.lean rename to Mathlib/AlgebraicGeometry/EllipticCurve/IsomOfJ.lean index 3a9bbae95d05d..3474c6e51b8e4 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/J.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/IsomOfJ.lean @@ -8,33 +8,32 @@ import Mathlib.FieldTheory.IsSepClosed /-! -# Further properties of j-invariants of elliptic curves - -This file states some further properties of j-invariants of elliptic curves. +# Elliptic curves with same j-invariants are isomorphic ## Main results -- `EllipticCurve.exists_variableChange_of_j_eq`: if `E` and `E'` are elliptic curves with the same - `j`-invariants defined over a separably closed field, then there exists a change of variables +- `WeierstrassCurve.exists_variableChange_of_j_eq`: if `E` and `E'` are elliptic curves with the + same `j`-invariants defined over a separably closed field, then there exists a change of variables over that field which change `E` into `E'`. -/ -open WeierstrassCurve Polynomial +open Polynomial variable {F : Type*} [Field F] [IsSepClosed F] -namespace EllipticCurve +namespace WeierstrassCurve -variable (E E' : EllipticCurve F) +variable (E E' : WeierstrassCurve F) [E.IsElliptic] [E'.IsElliptic] section CharTwo variable [CharP F 2] +omit [E.IsElliptic] [E'.IsElliptic] in private lemma exists_variableChange_of_char_two_of_j_ne_zero [E.IsCharTwoJNeZeroNF] [E'.IsCharTwoJNeZeroNF] (heq : E.a₆ = E'.a₆) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by obtain ⟨s, hs⟩ := IsSepClosed.exists_root_C_mul_X_pow_add_C_mul_X_add_C' 2 2 1 1 (E.a₂ + E'.a₂) (by norm_num) (by norm_num) one_ne_zero use ⟨1, 0, s, 0⟩ @@ -53,7 +52,7 @@ private lemma exists_variableChange_of_char_two_of_j_ne_zero private lemma exists_variableChange_of_char_two_of_j_eq_zero [E.IsCharTwoJEqZeroNF] [E'.IsCharTwoJEqZeroNF] : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by have ha₃ := E.Δ'.ne_zero rw [E.coe_Δ', Δ_of_isCharTwoJEqZeroNF_of_char_two, pow_ne_zero_iff (Nat.succ_ne_zero _)] at ha₃ have ha₃' := E'.Δ'.ne_zero @@ -86,7 +85,7 @@ private lemma exists_variableChange_of_char_two_of_j_eq_zero linear_combination ht - (t ^ 2 + E.a₃ * t) * CharP.cast_eq_zero F 2 private lemma exists_variableChange_of_char_two (heq : E.j = E'.j) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by obtain ⟨C, _ | _⟩ := E.exists_variableChange_isCharTwoNF · obtain ⟨C', _ | _⟩ := E'.exists_variableChange_isCharTwoNF · simp_rw [← variableChange_j E C, ← variableChange_j E' C', @@ -94,7 +93,7 @@ private lemma exists_variableChange_of_char_two (heq : E.j = E'.j) : obtain ⟨C'', hC⟩ := exists_variableChange_of_char_two_of_j_ne_zero _ _ heq use (C'.inv.comp C'').comp C rw [variableChange_comp, variableChange_comp, hC, ← variableChange_comp, - WeierstrassCurve.VariableChange.comp_left_inv, variableChange_id] + VariableChange.comp_left_inv, variableChange_id] · have h := (E.variableChange C).j_ne_zero_of_isCharTwoJNeZeroNF_of_char_two rw [variableChange_j, heq, ← variableChange_j E' C', j_of_isCharTwoJEqZeroNF_of_char_two] at h @@ -108,7 +107,7 @@ private lemma exists_variableChange_of_char_two (heq : E.j = E'.j) : (E.variableChange C) (E'.variableChange C') use (C'.inv.comp C'').comp C rw [variableChange_comp, variableChange_comp, hC, ← variableChange_comp, - WeierstrassCurve.VariableChange.comp_left_inv, variableChange_id] + VariableChange.comp_left_inv, variableChange_id] end CharTwo @@ -118,7 +117,7 @@ variable [CharP F 3] private lemma exists_variableChange_of_char_three_of_j_ne_zero [E.IsCharThreeJNeZeroNF] [E'.IsCharThreeJNeZeroNF] (heq : E.j = E'.j) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by have h := E.Δ'.ne_zero rw [E.coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three, mul_ne_zero_iff, neg_ne_zero, pow_ne_zero_iff three_ne_zero] at h @@ -155,7 +154,7 @@ private lemma exists_variableChange_of_char_three_of_j_ne_zero private lemma exists_variableChange_of_char_three_of_j_eq_zero [E.IsShortNF] [E'.IsShortNF] : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by have ha₄ := E.Δ'.ne_zero rw [E.coe_Δ', Δ_of_isShortNF_of_char_three, neg_ne_zero, pow_ne_zero_iff three_ne_zero] at ha₄ have ha₄' := E'.Δ'.ne_zero @@ -188,14 +187,14 @@ private lemma exists_variableChange_of_char_three_of_j_eq_zero linear_combination hr private lemma exists_variableChange_of_char_three (heq : E.j = E'.j) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by obtain ⟨C, _ | _⟩ := E.exists_variableChange_isCharThreeNF · obtain ⟨C', _ | _⟩ := E'.exists_variableChange_isCharThreeNF · rw [← variableChange_j E C, ← variableChange_j E' C'] at heq obtain ⟨C'', hC⟩ := exists_variableChange_of_char_three_of_j_ne_zero _ _ heq use (C'.inv.comp C'').comp C rw [variableChange_comp, variableChange_comp, hC, ← variableChange_comp, - WeierstrassCurve.VariableChange.comp_left_inv, variableChange_id] + VariableChange.comp_left_inv, variableChange_id] · have h := (E.variableChange C).j_ne_zero_of_isCharThreeJNeZeroNF_of_char_three rw [variableChange_j, heq, ← variableChange_j E' C', j_of_isShortNF_of_char_three] at h exact False.elim (h rfl) @@ -207,7 +206,7 @@ private lemma exists_variableChange_of_char_three (heq : E.j = E'.j) : (E.variableChange C) (E'.variableChange C') use (C'.inv.comp C'').comp C rw [variableChange_comp, variableChange_comp, hC, ← variableChange_comp, - WeierstrassCurve.VariableChange.comp_left_inv, variableChange_id] + VariableChange.comp_left_inv, variableChange_id] end CharThree @@ -215,7 +214,7 @@ section CharNeTwoOrThree private lemma exists_variableChange_of_char_ne_two_or_three {p : ℕ} [CharP F p] (hchar2 : p ≠ 2) (hchar3 : p ≠ 3) (heq : E.j = E'.j) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by replace hchar2 : (2 : F) ≠ 0 := CharP.cast_ne_zero_of_ne_of_prime F Nat.prime_two hchar2 replace hchar3 : (3 : F) ≠ 0 := CharP.cast_ne_zero_of_ne_of_prime F Nat.prime_three hchar3 haveI := NeZero.mk hchar2 @@ -239,7 +238,7 @@ private lemma exists_variableChange_of_char_ne_two_or_three rw [← variableChange_j E' C] at heq obtain ⟨C', hC⟩ := this _ heq hE' exact ⟨C.inv.comp C', by rw [variableChange_comp, hC, ← variableChange_comp, - WeierstrassCurve.VariableChange.comp_left_inv, variableChange_id]⟩ + VariableChange.comp_left_inv, variableChange_id]⟩ simp_rw [j, Units.val_inv_eq_inv_val, inv_mul_eq_div, div_eq_div_iff E.Δ'.ne_zero E'.Δ'.ne_zero, coe_Δ', Δ_of_isShortNF, c₄_of_isShortNF] at heq replace heq : E.a₄ ^ 3 * E'.a₆ ^ 2 = E'.a₄ ^ 3 * E.a₆ ^ 2 := by @@ -337,7 +336,7 @@ end CharNeTwoOrThree separably closed field, then there exists a change of variables over that field which change one curve into another. -/ theorem exists_variableChange_of_j_eq (heq : E.j = E'.j) : - ∃ C : WeierstrassCurve.VariableChange F, E.variableChange C = E' := by + ∃ C : VariableChange F, E.variableChange C = E' := by obtain ⟨p, _⟩ := CharP.exists F by_cases hchar2 : p = 2 · subst hchar2 @@ -347,4 +346,4 @@ theorem exists_variableChange_of_j_eq (heq : E.j = E'.j) : exact exists_variableChange_of_char_three _ _ heq exact exists_variableChange_of_char_ne_two_or_three _ _ hchar2 hchar3 heq -end EllipticCurve +end WeierstrassCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/ModelsWithJ.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/ModelsWithJ.lean new file mode 100644 index 0000000000000..31e52e81f9fef --- /dev/null +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/ModelsWithJ.lean @@ -0,0 +1,196 @@ +/- +Copyright (c) 2021 Kevin Buzzard. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kevin Buzzard, David Kurniadi Angdinata +-/ +import Mathlib.AlgebraicGeometry.EllipticCurve.Weierstrass + +/-! +# Models of elliptic curves with prescribed j-invariant + +This file defines the Weierstrass equation over a field with prescribed j-invariant, +proved that it is an elliptic curve, and that its j-invariant is equal to the given value. +It is a modification of [silverman2009], Chapter III, Proposition 1.4 (c). + +## Main definitions + + * `WeierstrassCurve.ofJ0`: an elliptic curve whose j-invariant is 0. + * `WeierstrassCurve.ofJ1728`: an elliptic curve whose j-invariant is 1728. + * `WeierstrassCurve.ofJNe0Or1728`: an elliptic curve whose j-invariant is neither 0 nor 1728. + * `WeierstrassCurve.ofJ`: an elliptic curve whose j-invariant equal to j. + +## Main statements + + * `WeierstrassCurve.ofJ_j`: the j-invariant of `WeierstrassCurve.ofJ` is equal to j. + +## References + + * [J Silverman, *The Arithmetic of Elliptic Curves*][silverman2009] + +## Tags + +elliptic curve, weierstrass equation, j invariant +-/ + +namespace WeierstrassCurve + +variable (R : Type*) [CommRing R] (W : WeierstrassCurve R) + +/-- The Weierstrass curve $Y^2 + Y = X^3$. It is of j-invariant 0 if it is an elliptic curve. -/ +def ofJ0 : WeierstrassCurve R := + ⟨0, 0, 1, 0, 0⟩ + +lemma ofJ0_c₄ : (ofJ0 R).c₄ = 0 := by + rw [ofJ0, c₄, b₂, b₄] + norm_num1 + +lemma ofJ0_Δ : (ofJ0 R).Δ = -27 := by + rw [ofJ0, Δ, b₂, b₄, b₆, b₈] + norm_num1 + +/-- The Weierstrass curve $Y^2 = X^3 + X$. It is of j-invariant 1728 if it is an elliptic curve. -/ +def ofJ1728 : WeierstrassCurve R := + ⟨0, 0, 0, 1, 0⟩ + +lemma ofJ1728_c₄ : (ofJ1728 R).c₄ = -48 := by + rw [ofJ1728, c₄, b₂, b₄] + norm_num1 + +lemma ofJ1728_Δ : (ofJ1728 R).Δ = -64 := by + rw [ofJ1728, Δ, b₂, b₄, b₆, b₈] + norm_num1 + +variable {R} (j : R) + +/-- The Weierstrass curve $Y^2 + (j - 1728)XY = X^3 - 36(j - 1728)^3X - (j - 1728)^5$. +It is a modification of the curve in [silverman2009], Chapter III, Proposition 1.4 (c) to avoid +denominators. It is of j-invariant j if it is an elliptic curve. -/ +def ofJNe0Or1728 : WeierstrassCurve R := + ⟨j - 1728, 0, 0, -36 * (j - 1728) ^ 3, -(j - 1728) ^ 5⟩ + +lemma ofJNe0Or1728_c₄ : (ofJNe0Or1728 j).c₄ = j * (j - 1728) ^ 3 := by + simp only [ofJNe0Or1728, c₄, b₂, b₄] + ring1 + +lemma ofJNe0Or1728_Δ : (ofJNe0Or1728 j).Δ = j ^ 2 * (j - 1728) ^ 9 := by + simp only [ofJNe0Or1728, Δ, b₂, b₄, b₆, b₈] + ring1 + +variable (R) [W.IsElliptic] + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +/-- When 3 is a unit, $Y^2 + Y = X^3$ is an elliptic curve. +It is of j-invariant 0 (see `WeierstrassCurve.ofJ0_j`). -/ +instance [hu : Fact (IsUnit (3 : R))] : (ofJ0 R).IsElliptic := by + rw [isElliptic_iff, ofJ0_Δ] + convert (hu.out.pow 3).neg + norm_num1 + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +lemma ofJ0_j [Fact (IsUnit (3 : R))] : (ofJ0 R).j = 0 := by + rw [j, ofJ0_c₄] + ring1 + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +/-- When 2 is a unit, $Y^2 = X^3 + X$ is an elliptic curve. +It is of j-invariant 1728 (see `WeierstrassCurve.ofJ1728_j`). -/ +instance [hu : Fact (IsUnit (2 : R))] : (ofJ1728 R).IsElliptic := by + rw [isElliptic_iff, ofJ1728_Δ] + convert (hu.out.pow 6).neg + norm_num1 + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +lemma ofJ1728_j [Fact (IsUnit (2 : R))] : (ofJ1728 R).j = 1728 := by + rw [j, Units.inv_mul_eq_iff_eq_mul, ofJ1728_c₄, coe_Δ', ofJ1728_Δ] + norm_num1 + +variable {R} + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +/-- When j and j - 1728 are both units, +$Y^2 + (j - 1728)XY = X^3 - 36(j - 1728)^3X - (j - 1728)^5$ is an elliptic curve. +It is of j-invariant j (see `WeierstrassCurve.ofJNe0Or1728_j`). -/ +instance (j : R) [h1 : Fact (IsUnit j)] [h2 : Fact (IsUnit (j - 1728))] : + (ofJNe0Or1728 j).IsElliptic := by + rw [isElliptic_iff, ofJNe0Or1728_Δ] + exact (h1.out.pow 2).mul (h2.out.pow 9) + +-- TODO: change to `[IsUnit ...]` once #17458 is merged +lemma ofJNe0Or1728_j (j : R) [Fact (IsUnit j)] [Fact (IsUnit (j - 1728))] : + (ofJNe0Or1728 j).j = j := by + rw [WeierstrassCurve.j, Units.inv_mul_eq_iff_eq_mul, ofJNe0Or1728_c₄, coe_Δ', ofJNe0Or1728_Δ] + ring1 + +variable {F : Type*} [Field F] (j : F) [DecidableEq F] + +/-- For any element j of a field $F$, there exists an elliptic curve over $F$ +with j-invariant equal to j (see `WeierstrassCurve.ofJ_j`). +Its coefficients are given explicitly (see `WeierstrassCurve.ofJ0`, `WeierstrassCurve.ofJ1728` +and `WeierstrassCurve.ofJNe0Or1728`). -/ +def ofJ : WeierstrassCurve F := + if j = 0 then if (3 : F) = 0 then ofJ1728 F else ofJ0 F + else if j = 1728 then ofJ1728 F else ofJNe0Or1728 j + +lemma ofJ_0_of_three_ne_zero (h3 : (3 : F) ≠ 0) : ofJ 0 = ofJ0 F := by + rw [ofJ, if_pos rfl, if_neg h3] + +lemma ofJ_0_of_three_eq_zero (h3 : (3 : F) = 0) : ofJ 0 = ofJ1728 F := by + rw [ofJ, if_pos rfl, if_pos h3] + +lemma ofJ_0_of_two_eq_zero (h2 : (2 : F) = 0) : ofJ 0 = ofJ0 F := by + rw [ofJ, if_pos rfl, if_neg ((show (3 : F) = 1 by linear_combination h2) ▸ one_ne_zero)] + +lemma ofJ_1728_of_three_eq_zero (h3 : (3 : F) = 0) : ofJ 1728 = ofJ1728 F := by + rw [ofJ, if_pos (by linear_combination 576 * h3), if_pos h3] + +lemma ofJ_1728_of_two_ne_zero (h2 : (2 : F) ≠ 0) : ofJ 1728 = ofJ1728 F := by + by_cases h3 : (3 : F) = 0 + · exact ofJ_1728_of_three_eq_zero h3 + · rw [ofJ, show (1728 : F) = 2 ^ 6 * 3 ^ 3 by norm_num1, + if_neg (mul_ne_zero (pow_ne_zero 6 h2) (pow_ne_zero 3 h3)), if_pos rfl] + +lemma ofJ_1728_of_two_eq_zero (h2 : (2 : F) = 0) : ofJ 1728 = ofJ0 F := by + rw [ofJ, if_pos (by linear_combination 864 * h2), + if_neg ((show (3 : F) = 1 by linear_combination h2) ▸ one_ne_zero)] + +lemma ofJ_ne_0_ne_1728 (h0 : j ≠ 0) (h1728 : j ≠ 1728) : ofJ j = ofJNe0Or1728 j := by + rw [ofJ, if_neg h0, if_neg h1728] + +instance : (ofJ j).IsElliptic := by + by_cases h0 : j = 0 + · by_cases h3 : (3 : F) = 0 + · have := Fact.mk (isUnit_of_mul_eq_one (2 : F) 2 (by linear_combination h3)) + rw [h0, ofJ_0_of_three_eq_zero h3] + infer_instance + · have := Fact.mk (Ne.isUnit h3) + rw [h0, ofJ_0_of_three_ne_zero h3] + infer_instance + · by_cases h1728 : j = 1728 + · have h2 : (2 : F) ≠ 0 := fun h ↦ h0 (by linear_combination h1728 + 864 * h) + have := Fact.mk h2.isUnit + rw [h1728, ofJ_1728_of_two_ne_zero h2] + infer_instance + · have := Fact.mk (Ne.isUnit h0) + have := Fact.mk (sub_ne_zero.2 h1728).isUnit + rw [ofJ_ne_0_ne_1728 j h0 h1728] + infer_instance + +lemma ofJ_j : (ofJ j).j = j := by + by_cases h0 : j = 0 + · by_cases h3 : (3 : F) = 0 + · have := Fact.mk (isUnit_of_mul_eq_one (2 : F) 2 (by linear_combination h3)) + simp_rw [h0, ofJ_0_of_three_eq_zero h3, ofJ1728_j] + linear_combination 576 * h3 + · have := Fact.mk (Ne.isUnit h3) + simp_rw [h0, ofJ_0_of_three_ne_zero h3, ofJ0_j] + · by_cases h1728 : j = 1728 + · have h2 : (2 : F) ≠ 0 := fun h ↦ h0 (by linear_combination h1728 + 864 * h) + have := Fact.mk h2.isUnit + simp_rw [h1728, ofJ_1728_of_two_ne_zero h2, ofJ1728_j] + · have := Fact.mk (Ne.isUnit h0) + have := Fact.mk (sub_ne_zero.2 h1728).isUnit + simp_rw [ofJ_ne_0_ne_1728 j h0 h1728, ofJNe0Or1728_j] + +instance : Inhabited { W : WeierstrassCurve F // W.IsElliptic } := ⟨⟨ofJ 37, inferInstance⟩⟩ + +end WeierstrassCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean index 23a9a69744985..5738f216555e7 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/NormalForms.lean @@ -92,8 +92,7 @@ elliptic curve, weierstrass equation, normal form -/ -variable {R : Type*} [CommRing R] (W : WeierstrassCurve R) -variable {F : Type*} [Field F] (E : EllipticCurve F) +variable {R : Type*} [CommRing R] {F : Type*} [Field F] (W : WeierstrassCurve R) namespace WeierstrassCurve @@ -156,7 +155,7 @@ end Quantity section VariableChange -variable (E : EllipticCurve R) [Invertible (2 : R)] +variable [Invertible (2 : R)] /-- There is an explicit change of variables of a `WeierstrassCurve` to a normal form of characteristic ≠ 2, provided that 2 is invertible in the ring. -/ @@ -170,14 +169,6 @@ theorem exists_variableChange_isCharNeTwoNF : ∃ C : VariableChange R, (W.variableChange C).IsCharNeTwoNF := ⟨_, W.toCharNeTwoNF_spec⟩ -instance _root_.EllipticCurve.toCharNeTwoNF_spec : - (E.variableChange E.toCharNeTwoNF).IsCharNeTwoNF := - E.toWeierstrassCurve.toCharNeTwoNF_spec - -theorem _root_.EllipticCurve.exists_variableChange_isCharNeTwoNF : - ∃ C : VariableChange R, (E.variableChange C).IsCharNeTwoNF := - ⟨_, E.toCharNeTwoNF_spec⟩ - end VariableChange /-! ### Short normal form -/ @@ -248,25 +239,24 @@ theorem Δ_of_isShortNF_of_char_three : W.Δ = -W.a₄ ^ 3 := by rw [Δ_of_isShortNF] linear_combination (-21 * W.a₄ ^ 3 - 144 * W.a₆ ^ 2) * CharP.cast_eq_zero R 3 -variable [E.IsShortNF] +variable (W : WeierstrassCurve F) [W.IsElliptic] [W.IsShortNF] -theorem _root_.EllipticCurve.j_of_isShortNF : - E.j = 6912 * E.a₄ ^ 3 / (4 * E.a₄ ^ 3 + 27 * E.a₆ ^ 2) := by - have h := E.Δ'.ne_zero - rw [E.coe_Δ', Δ_of_isShortNF] at h - rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ', +theorem j_of_isShortNF : W.j = 6912 * W.a₄ ^ 3 / (4 * W.a₄ ^ 3 + 27 * W.a₆ ^ 2) := by + have h := W.Δ'.ne_zero + rw [coe_Δ', Δ_of_isShortNF] at h + rw [j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, coe_Δ', c₄_of_isShortNF, Δ_of_isShortNF, div_eq_div_iff h (right_ne_zero_of_mul h)] ring1 @[simp] -theorem _root_.EllipticCurve.j_of_isShortNF_of_char_three [CharP F 3] : E.j = 0 := by - rw [EllipticCurve.j, c₄_of_isShortNF_of_char_three]; simp +theorem j_of_isShortNF_of_char_three [CharP F 3] : W.j = 0 := by + rw [j, c₄_of_isShortNF_of_char_three]; simp end Quantity section VariableChange -variable (E : EllipticCurve R) [Invertible (2 : R)] [Invertible (3 : R)] +variable [Invertible (2 : R)] [Invertible (3 : R)] /-- There is an explicit change of variables of a `WeierstrassCurve` to a short normal form, provided that 2 and 3 are invertible in the ring. @@ -282,13 +272,6 @@ theorem exists_variableChange_isShortNF : ∃ C : VariableChange R, (W.variableChange C).IsShortNF := ⟨_, W.toShortNF_spec⟩ -instance _root_.EllipticCurve.toShortNF_spec : (E.variableChange E.toShortNF).IsShortNF := - E.toWeierstrassCurve.toShortNF_spec - -theorem _root_.EllipticCurve.exists_variableChange_isShortNF : - ∃ C : VariableChange R, (E.variableChange C).IsShortNF := - ⟨_, E.toShortNF_spec⟩ - end VariableChange /-! ### Normal forms of characteristic = 3 and j ≠ 0 -/ @@ -360,21 +343,21 @@ theorem Δ_of_isCharThreeJNeZeroNF_of_char_three : W.Δ = -W.a₂ ^ 3 * W.a₆ : rw [Δ_of_isCharThreeJNeZeroNF] linear_combination (-21 * W.a₂ ^ 3 * W.a₆ - 144 * W.a₆ ^ 2) * CharP.cast_eq_zero R 3 -variable [E.IsCharThreeJNeZeroNF] [CharP F 3] +variable (W : WeierstrassCurve F) [W.IsElliptic] [W.IsCharThreeJNeZeroNF] [CharP F 3] @[simp] -theorem _root_.EllipticCurve.j_of_isCharThreeJNeZeroNF_of_char_three : E.j = -E.a₂ ^ 3 / E.a₆ := by - have h := E.Δ'.ne_zero - rw [E.coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three] at h - rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ', +theorem j_of_isCharThreeJNeZeroNF_of_char_three : W.j = -W.a₂ ^ 3 / W.a₆ := by + have h := W.Δ'.ne_zero + rw [coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three] at h + rw [j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, coe_Δ', c₄_of_isCharThreeJNeZeroNF_of_char_three, Δ_of_isCharThreeJNeZeroNF_of_char_three, div_eq_div_iff h (right_ne_zero_of_mul h)] ring1 -theorem _root_.EllipticCurve.j_ne_zero_of_isCharThreeJNeZeroNF_of_char_three : E.j ≠ 0 := by - rw [E.j_of_isCharThreeJNeZeroNF_of_char_three, div_ne_zero_iff] - have h := E.Δ'.ne_zero - rwa [E.coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three, mul_ne_zero_iff] at h +theorem j_ne_zero_of_isCharThreeJNeZeroNF_of_char_three : W.j ≠ 0 := by + rw [j_of_isCharThreeJNeZeroNF_of_char_three, div_ne_zero_iff] + have h := W.Δ'.ne_zero + rwa [coe_Δ', Δ_of_isCharThreeJNeZeroNF_of_char_three, mul_ne_zero_iff] at h end Quantity @@ -420,10 +403,6 @@ theorem toShortNFOfCharThree_spec (hb₂ : W.b₂ = 0) : have H := W.toCharNeTwoNF_spec exact ⟨H.a₁, hb₂ ▸ W.toShortNFOfCharThree_a₂, H.a₃⟩ -theorem _root_.EllipticCurve.toShortNFOfCharThree_spec (E : EllipticCurve R) (hb₂ : E.b₂ = 0) : - (E.variableChange E.toShortNFOfCharThree).IsShortNF := - E.toWeierstrassCurve.toShortNFOfCharThree_spec hb₂ - variable (W : WeierstrassCurve F) /-- For a `WeierstrassCurve` defined over a field of characteristic = 3, @@ -455,14 +434,6 @@ theorem toCharThreeNF_spec_of_b₂_eq_zero (hb₂ : W.b₂ = 0) : VariableChange.id_comp] exact W.toShortNFOfCharThree_spec hb₂ -theorem _root_.EllipticCurve.toCharThreeNF_spec_of_b₂_ne_zero (hb₂ : E.b₂ ≠ 0) : - (E.variableChange E.toCharThreeNF).IsCharThreeJNeZeroNF := - E.toWeierstrassCurve.toCharThreeNF_spec_of_b₂_ne_zero hb₂ - -theorem _root_.EllipticCurve.toCharThreeNF_spec_of_b₂_eq_zero (hb₂ : E.b₂ = 0) : - (E.variableChange E.toCharThreeNF).IsShortNF := - E.toWeierstrassCurve.toCharThreeNF_spec_of_b₂_eq_zero hb₂ - instance toCharThreeNF_spec : (W.variableChange W.toCharThreeNF).IsCharThreeNF := by by_cases hb₂ : W.b₂ = 0 · haveI := W.toCharThreeNF_spec_of_b₂_eq_zero hb₂ @@ -474,14 +445,6 @@ theorem exists_variableChange_isCharThreeNF : ∃ C : VariableChange F, (W.variableChange C).IsCharThreeNF := ⟨_, W.toCharThreeNF_spec⟩ -instance _root_.EllipticCurve.toCharThreeNF_spec : - (E.variableChange E.toCharThreeNF).IsCharThreeNF := - E.toWeierstrassCurve.toCharThreeNF_spec - -theorem _root_.EllipticCurve.exists_variableChange_isCharThreeNF : - ∃ C : VariableChange F, (E.variableChange C).IsCharThreeNF := - ⟨_, E.toCharThreeNF_spec⟩ - end VariableChange /-! ### Normal forms of characteristic = 2 and j ≠ 0 -/ @@ -565,17 +528,17 @@ theorem Δ_of_isCharTwoJNeZeroNF_of_char_two : W.Δ = W.a₆ := by b₆_of_isCharTwoJNeZeroNF_of_char_two, b₈_of_isCharTwoJNeZeroNF_of_char_two] linear_combination -W.a₆ * CharP.cast_eq_zero R 2 -variable [E.IsCharTwoJNeZeroNF] [CharP F 2] +variable (W : WeierstrassCurve F) [W.IsElliptic] [W.IsCharTwoJNeZeroNF] [CharP F 2] @[simp] -theorem _root_.EllipticCurve.j_of_isCharTwoJNeZeroNF_of_char_two : E.j = 1 / E.a₆ := by - rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ', +theorem j_of_isCharTwoJNeZeroNF_of_char_two : W.j = 1 / W.a₆ := by + rw [j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, coe_Δ', c₄_of_isCharTwoJNeZeroNF_of_char_two, Δ_of_isCharTwoJNeZeroNF_of_char_two, one_pow] -theorem _root_.EllipticCurve.j_ne_zero_of_isCharTwoJNeZeroNF_of_char_two : E.j ≠ 0 := by - rw [E.j_of_isCharTwoJNeZeroNF_of_char_two, div_ne_zero_iff] - have h := E.Δ'.ne_zero - rw [E.coe_Δ', Δ_of_isCharTwoJNeZeroNF_of_char_two] at h +theorem j_ne_zero_of_isCharTwoJNeZeroNF_of_char_two : W.j ≠ 0 := by + rw [j_of_isCharTwoJNeZeroNF_of_char_two, div_ne_zero_iff] + have h := W.Δ'.ne_zero + rw [coe_Δ', Δ_of_isCharTwoJNeZeroNF_of_char_two] at h exact ⟨one_ne_zero, h⟩ end Quantity @@ -651,19 +614,18 @@ theorem Δ_of_isCharTwoJEqZeroNF_of_char_two : W.Δ = W.a₃ ^ 4 := by rw [Δ_of_isCharTwoJEqZeroNF, b₆_of_char_two] linear_combination (-32 * W.a₄ ^ 3 - 14 * W.a₃ ^ 4) * CharP.cast_eq_zero R 2 -variable [E.IsCharTwoJEqZeroNF] +variable (W : WeierstrassCurve F) [W.IsElliptic] [W.IsCharTwoJEqZeroNF] -theorem _root_.EllipticCurve.j_of_isCharTwoJEqZeroNF : - E.j = 110592 * E.a₄ ^ 3 / (64 * E.a₄ ^ 3 + 27 * E.b₆ ^ 2) := by - have h := E.Δ'.ne_zero - rw [E.coe_Δ', Δ_of_isCharTwoJEqZeroNF] at h - rw [EllipticCurve.j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, E.coe_Δ', +theorem j_of_isCharTwoJEqZeroNF : W.j = 110592 * W.a₄ ^ 3 / (64 * W.a₄ ^ 3 + 27 * W.b₆ ^ 2) := by + have h := W.Δ'.ne_zero + rw [coe_Δ', Δ_of_isCharTwoJEqZeroNF] at h + rw [j, Units.val_inv_eq_inv_val, ← div_eq_inv_mul, coe_Δ', c₄_of_isCharTwoJEqZeroNF, Δ_of_isCharTwoJEqZeroNF, div_eq_div_iff h (neg_ne_zero.1 h)] ring1 @[simp] -theorem _root_.EllipticCurve.j_of_isCharTwoJEqZeroNF_of_char_two [CharP F 2] : E.j = 0 := by - rw [EllipticCurve.j, c₄_of_isCharTwoJEqZeroNF_of_char_two]; simp +theorem j_of_isCharTwoJEqZeroNF_of_char_two [CharP F 2] : W.j = 0 := by + rw [j, c₄_of_isCharTwoJEqZeroNF_of_char_two]; simp end Quantity @@ -698,10 +660,6 @@ theorem toCharTwoJEqZeroNF_spec (ha₁ : W.a₁ = 0) : · simp_rw [toCharTwoJEqZeroNF, variableChange_a₂, inv_one, Units.val_one] linear_combination 2 * W.a₂ * CharP.cast_eq_zero R 2 -theorem _root_.EllipticCurve.toCharTwoJEqZeroNF_spec (E : EllipticCurve R) (ha₁ : E.a₁ = 0) : - (E.variableChange E.toCharTwoJEqZeroNF).IsCharTwoJEqZeroNF := - E.toWeierstrassCurve.toCharTwoJEqZeroNF_spec ha₁ - variable (W : WeierstrassCurve F) /-- For a `WeierstrassCurve` defined over a field of characteristic = 2, @@ -719,10 +677,6 @@ theorem toCharTwoJNeZeroNF_spec (ha₁ : W.a₁ ≠ 0) : · field_simp [toCharTwoJNeZeroNF] linear_combination (W.a₁ ^ 4 * W.a₃ ^ 2 + W.a₁ ^ 5 * W.a₃ * W.a₂) * CharP.cast_eq_zero F 2 -theorem _root_.EllipticCurve.toCharTwoJNeZeroNF_spec (ha₁ : E.a₁ ≠ 0) : - (E.variableChange (E.toCharTwoJNeZeroNF ha₁)).IsCharTwoJNeZeroNF := - E.toWeierstrassCurve.toCharTwoJNeZeroNF_spec ha₁ - /-- For a `WeierstrassCurve` defined over a field of characteristic = 2, there is an explicit change of variables of it to `WeierstrassCurve.IsCharTwoNF`, that is, $Y^2 + XY = X^3 + a_2X^2 + a_6$ (`WeierstrassCurve.IsCharTwoJNeZeroNF`) or @@ -744,15 +698,6 @@ theorem exists_variableChange_isCharTwoNF : classical exact ⟨_, W.toCharTwoNF_spec⟩ -instance _root_.EllipticCurve.toCharTwoNF_spec [DecidableEq F] : - (E.variableChange E.toCharTwoNF).IsCharTwoNF := - E.toWeierstrassCurve.toCharTwoNF_spec - -theorem _root_.EllipticCurve.exists_variableChange_isCharTwoNF : - ∃ C : VariableChange F, (E.variableChange C).IsCharTwoNF := by - classical - exact ⟨_, E.toCharTwoNF_spec⟩ - end VariableChange end WeierstrassCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean index 77ea4968688e9..5ee45845ec6d1 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/VariableChange.lean @@ -13,14 +13,13 @@ This file defines admissible linear change of variables of Weierstrass curves. ## Main definitions * `WeierstrassCurve.VariableChange`: a change of variables of Weierstrass curves. + * `WeierstrassCurve.VariableChange.instGroup`: change of variables form a group. * `WeierstrassCurve.variableChange`: the Weierstrass curve induced by a change of variables. * `WeierstrassCurve.instMulActionVariableChange`: change of variables act on Weierstrass curves. - * `EllipticCurve.variableChange`: the elliptic curve induced by a change of variables. - * `EllipticCurve.instMulActionVariableChange`: change of variables act on elliptic curves. ## Main statements - * `EllipticCurve.variableChange_j`: the j-invariant of an elliptic curve is invariant under an + * `WeierstrassCurve.variableChange_j`: the j-invariant of an elliptic curve is invariant under an admissible linear change of variables. ## References @@ -47,7 +46,9 @@ section VariableChange /-- An admissible linear change of variables of Weierstrass curves defined over a ring `R` given by a tuple $(u, r, s, t)$ for some $u \in R^\times$ and some $r, s, t \in R$. As a matrix, it is -$\begin{pmatrix} u^2 & 0 & r \cr u^2s & u^3 & t \cr 0 & 0 & 1 \end{pmatrix}$. -/ +$\begin{pmatrix} u^2 & 0 & r \cr u^2s & u^3 & t \cr 0 & 0 & 1 \end{pmatrix}$. +In other words, this is the change of variables $(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$. +When `R` is a field, any two isomorphic Weierstrass equations are related by this. -/ @[ext] structure VariableChange (R : Type u) [CommRing R] where /-- The `u` coefficient of an admissible linear change of variables, which must be a unit. -/ @@ -91,9 +92,9 @@ lemma comp_left_inv (C : VariableChange R) : comp (inv C) C = id := by rw [comp, id, inv] ext <;> dsimp only · exact C.u.inv_mul - · linear_combination (norm := ring1) -C.r * pow_mul_pow_eq_one 2 C.u.inv_mul - · linear_combination (norm := ring1) -C.s * C.u.inv_mul - · linear_combination (norm := ring1) (C.r * C.s - C.t) * pow_mul_pow_eq_one 3 C.u.inv_mul + · linear_combination -C.r * pow_mul_pow_eq_one 2 C.u.inv_mul + · linear_combination -C.s * C.u.inv_mul + · linear_combination (C.r * C.s - C.t) * pow_mul_pow_eq_one 3 C.u.inv_mul + -C.r * C.s * pow_mul_pow_eq_one 2 C.u.inv_mul lemma comp_assoc (C C' C'' : VariableChange R) : comp (comp C C') C'' = comp C (comp C' C'') := by @@ -132,21 +133,21 @@ lemma variableChange_comp (C C' : VariableChange R) (W : WeierstrassCurve R) : W.variableChange (C.comp C') = (W.variableChange C').variableChange C := by simp only [VariableChange.comp, variableChange] ext <;> simp only [mul_inv, Units.val_mul] - · linear_combination (norm := ring1) ↑C.u⁻¹ * C.s * 2 * C'.u.inv_mul - · linear_combination (norm := ring1) + · linear_combination ↑C.u⁻¹ * C.s * 2 * C'.u.inv_mul + · linear_combination C.s * (-C'.s * 2 - W.a₁) * C.u⁻¹ ^ 2 * ↑C'.u⁻¹ * C'.u.inv_mul + (C.r * 3 - C.s ^ 2) * C.u⁻¹ ^ 2 * pow_mul_pow_eq_one 2 C'.u.inv_mul - · linear_combination (norm := ring1) + · linear_combination C.r * (C'.s * 2 + W.a₁) * C.u⁻¹ ^ 3 * ↑C'.u⁻¹ * pow_mul_pow_eq_one 2 C'.u.inv_mul + C.t * 2 * C.u⁻¹ ^ 3 * pow_mul_pow_eq_one 3 C'.u.inv_mul - · linear_combination (norm := ring1) + · linear_combination C.s * (-W.a₃ - C'.r * W.a₁ - C'.t * 2) * C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 3 * C'.u.inv_mul + C.u⁻¹ ^ 4 * C'.u⁻¹ ^ 2 * (C.r * C'.r * 6 + C.r * W.a₂ * 2 - C'.s * C.r * W.a₁ * 2 - C'.s ^ 2 * C.r * 2) * pow_mul_pow_eq_one 2 C'.u.inv_mul - C.u⁻¹ ^ 4 * ↑C'.u⁻¹ * (C.s * C'.s * C.r * 2 + C.s * C.r * W.a₁ + C'.s * C.t * 2 + C.t * W.a₁) * pow_mul_pow_eq_one 3 C'.u.inv_mul + C.u⁻¹ ^ 4 * (C.r ^ 2 * 3 - C.s * C.t * 2) * pow_mul_pow_eq_one 4 C'.u.inv_mul - · linear_combination (norm := ring1) + · linear_combination C.r * C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 4 * (C'.r * W.a₂ * 2 - C'.r * C'.s * W.a₁ + C'.r ^ 2 * 3 + W.a₄ - C'.s * C'.t * 2 - C'.s * W.a₃ - C'.t * W.a₁) * pow_mul_pow_eq_one 2 C'.u.inv_mul - C.u⁻¹ ^ 6 * C'.u⁻¹ ^ 3 * C.t * (C'.r * W.a₁ + C'.t * 2 + W.a₃) @@ -201,6 +202,34 @@ lemma variableChange_Δ : (W.variableChange C).Δ = C.u⁻¹ ^ 12 * W.Δ := by variableChange_a₄, variableChange_a₆] ring1 +variable [W.IsElliptic] + +instance : (W.variableChange C).IsElliptic := by + rw [isElliptic_iff, variableChange_Δ] + exact (C.u⁻¹.isUnit.pow 12).mul W.isUnit_Δ + +set_option linter.docPrime false in +@[simp] +lemma variableChange_Δ' : (W.variableChange C).Δ' = C.u⁻¹ ^ 12 * W.Δ' := by + simp_rw [Units.ext_iff, Units.val_mul, coe_Δ', variableChange_Δ, Units.val_pow_eq_pow_val] + +set_option linter.docPrime false in +lemma coe_variableChange_Δ' : ((W.variableChange C).Δ' : R) = C.u⁻¹ ^ 12 * W.Δ' := by + simp_rw [coe_Δ', variableChange_Δ] + +set_option linter.docPrime false in +lemma inv_variableChange_Δ' : (W.variableChange C).Δ'⁻¹ = C.u ^ 12 * W.Δ'⁻¹ := by + rw [variableChange_Δ', mul_inv, inv_pow, inv_inv] + +set_option linter.docPrime false in +lemma coe_inv_variableChange_Δ' : (↑(W.variableChange C).Δ'⁻¹ : R) = C.u ^ 12 * W.Δ'⁻¹ := by + rw [inv_variableChange_Δ', Units.val_mul, Units.val_pow_eq_pow_val] + +@[simp] +lemma variableChange_j : (W.variableChange C).j = W.j := by + rw [j, coe_inv_variableChange_Δ', variableChange_c₄, j, mul_pow, ← pow_mul, ← mul_assoc, + mul_right_comm (C.u.val ^ 12), ← mul_pow, C.u.mul_inv, one_pow, one_mul] + end VariableChange section BaseChange @@ -270,56 +299,3 @@ lemma map_variableChange (C : VariableChange R) : end BaseChange end WeierstrassCurve - -/-! ## Variable changes of elliptic curves -/ - -namespace EllipticCurve - -variable {R : Type u} [CommRing R] - -variable (E : EllipticCurve R) - -section VariableChange - -variable (C : WeierstrassCurve.VariableChange R) - --- Porting note: was just `@[simps]` -/-- The elliptic curve over `R` induced by an admissible linear change of variables -$(X, Y) \mapsto (u^2X + r, u^3Y + u^2sX + t)$ for some $u \in R^\times$ and some $r, s, t \in R$. -When `R` is a field, any two Weierstrass equations isomorphic to `E` are related by this. -/ -@[simps (config := { rhsMd := .default }) a₁ a₂ a₃ a₄ a₆ Δ' toWeierstrassCurve] -def variableChange : EllipticCurve R := - ⟨E.toWeierstrassCurve.variableChange C, C.u⁻¹ ^ 12 * E.Δ', by - rw [Units.val_mul, Units.val_pow_eq_pow_val, coe_Δ', E.variableChange_Δ]⟩ - -lemma variableChange_id : E.variableChange WeierstrassCurve.VariableChange.id = E := by - simp only [variableChange, WeierstrassCurve.variableChange_id] - simp only [WeierstrassCurve.VariableChange.id, inv_one, one_pow, one_mul] - -lemma variableChange_comp (C C' : WeierstrassCurve.VariableChange R) (E : EllipticCurve R) : - E.variableChange (C.comp C') = (E.variableChange C').variableChange C := by - simp only [variableChange, WeierstrassCurve.variableChange_comp] - simp only [WeierstrassCurve.VariableChange.comp, mul_inv, mul_pow, ← mul_assoc] - -instance instMulActionVariableChange : - MulAction (WeierstrassCurve.VariableChange R) (EllipticCurve R) where - smul := fun C E => E.variableChange C - one_smul := variableChange_id - mul_smul := variableChange_comp - -lemma coe_variableChange_Δ' : (E.variableChange C).Δ' = C.u⁻¹ ^ 12 * E.Δ' := - rfl - -lemma coe_inv_variableChange_Δ' : (E.variableChange C).Δ'⁻¹ = C.u ^ 12 * E.Δ'⁻¹ := by - rw [variableChange_Δ', mul_inv, inv_pow, inv_inv] - -@[simp] -lemma variableChange_j : (E.variableChange C).j = E.j := by - rw [j, coe_inv_variableChange_Δ', Units.val_mul, Units.val_pow_eq_pow_val, - variableChange_toWeierstrassCurve, WeierstrassCurve.variableChange_c₄] - have hu : (C.u * C.u⁻¹ : R) ^ 12 = 1 := by rw [C.u.mul_inv, one_pow] - linear_combination (norm := (rw [j]; ring1)) E.j * hu - -end VariableChange - -end EllipticCurve diff --git a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean index dcdc6fa4499d6..7265241ac9573 100644 --- a/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean +++ b/Mathlib/AlgebraicGeometry/EllipticCurve/Weierstrass.lean @@ -32,23 +32,15 @@ splitting field of `R` are precisely the $X$-coordinates of the non-zero 2-torsi * `WeierstrassCurve`: a Weierstrass curve over a commutative ring. * `WeierstrassCurve.Δ`: the discriminant of a Weierstrass curve. - * `WeierstrassCurve.ofJ0`: a Weierstrass curve whose j-invariant is 0. - * `WeierstrassCurve.ofJ1728`: a Weierstrass curve whose j-invariant is 1728. - * `WeierstrassCurve.ofJ`: a Weierstrass curve whose j-invariant is neither 0 nor 1728. * `WeierstrassCurve.map`: the Weierstrass curve mapped over a ring homomorphism. * `WeierstrassCurve.twoTorsionPolynomial`: the 2-torsion polynomial of a Weierstrass curve. - * `EllipticCurve`: an elliptic curve over a commutative ring. - * `EllipticCurve.j`: the j-invariant of an elliptic curve. - * `EllipticCurve.ofJ0`: an elliptic curve whose j-invariant is 0. - * `EllipticCurve.ofJ1728`: an elliptic curve whose j-invariant is 1728. - * `EllipticCurve.ofJ'`: an elliptic curve whose j-invariant is neither 0 nor 1728. - * `EllipticCurve.ofJ`: an elliptic curve whose j-invariant equal to j. + * `WeierstrassCurve.IsElliptic`: typeclass asserting that a Weierstrass curve is an elliptic curve. + * `WeierstrassCurve.j`: the j-invariant of an elliptic curve. ## Main statements * `WeierstrassCurve.twoTorsionPolynomial_disc`: the discriminant of a Weierstrass curve is a constant factor of the cubic discriminant of its 2-torsion polynomial. - * `EllipticCurve.ofJ_j`: the j-invariant of `EllipticCurve.ofJ` is equal to j. ## Implementation notes @@ -345,122 +337,75 @@ lemma twoTorsionPolynomial_disc_of_char_three : W.twoTorsionPolynomial.disc = W. end CharThree -lemma twoTorsionPolynomial_disc_isUnit [Invertible (2 : R)] : +-- TODO: change to `[IsUnit ...]` once #17458 is merged +lemma twoTorsionPolynomial_disc_isUnit (hu : IsUnit (2 : R)) : IsUnit W.twoTorsionPolynomial.disc ↔ IsUnit W.Δ := by rw [twoTorsionPolynomial_disc, IsUnit.mul_iff, show (16 : R) = 2 ^ 4 by norm_num1] - exact and_iff_right <| isUnit_of_invertible <| 2 ^ 4 + exact and_iff_right <| hu.pow 4 -lemma twoTorsionPolynomial_disc_ne_zero [Nontrivial R] [Invertible (2 : R)] (hΔ : IsUnit W.Δ) : +-- TODO: change to `[IsUnit ...]` once #17458 is merged +-- TODO: In this case `IsUnit W.Δ` is just `W.IsElliptic`, consider removing/rephrasing this result +lemma twoTorsionPolynomial_disc_ne_zero [Nontrivial R] (hu : IsUnit (2 : R)) (hΔ : IsUnit W.Δ) : W.twoTorsionPolynomial.disc ≠ 0 := - (W.twoTorsionPolynomial_disc_isUnit.mpr hΔ).ne_zero + ((W.twoTorsionPolynomial_disc_isUnit hu).mpr hΔ).ne_zero end TorsionPolynomial -section ModelsWithJ - -/-! ### Models with prescribed j-invariant -/ - -variable (R) - -/-- The Weierstrass curve $Y^2 + Y = X^3$. It is of j-invariant 0 if it is an elliptic curve. -/ -def ofJ0 : WeierstrassCurve R := - ⟨0, 0, 1, 0, 0⟩ - -lemma ofJ0_c₄ : (ofJ0 R).c₄ = 0 := by - rw [ofJ0, c₄, b₂, b₄] - norm_num1 - -lemma ofJ0_Δ : (ofJ0 R).Δ = -27 := by - rw [ofJ0, Δ, b₂, b₄, b₆, b₈] - norm_num1 - -/-- The Weierstrass curve $Y^2 = X^3 + X$. It is of j-invariant 1728 if it is an elliptic curve. -/ -def ofJ1728 : WeierstrassCurve R := - ⟨0, 0, 0, 1, 0⟩ - -lemma ofJ1728_c₄ : (ofJ1728 R).c₄ = -48 := by - rw [ofJ1728, c₄, b₂, b₄] - norm_num1 - -lemma ofJ1728_Δ : (ofJ1728 R).Δ = -64 := by - rw [ofJ1728, Δ, b₂, b₄, b₆, b₈] - norm_num1 - -variable {R} (j : R) - -/-- The Weierstrass curve $Y^2 + (j - 1728)XY = X^3 - 36(j - 1728)^3X - (j - 1728)^5$. -It is of j-invariant j if it is an elliptic curve. -/ -def ofJ : WeierstrassCurve R := - ⟨j - 1728, 0, 0, -36 * (j - 1728) ^ 3, -(j - 1728) ^ 5⟩ - -lemma ofJ_c₄ : (ofJ j).c₄ = j * (j - 1728) ^ 3 := by - simp only [ofJ, c₄, b₂, b₄] - ring1 - -lemma ofJ_Δ : (ofJ j).Δ = j ^ 2 * (j - 1728) ^ 9 := by - simp only [ofJ, Δ, b₂, b₄, b₆, b₈] - ring1 - -end ModelsWithJ - -end WeierstrassCurve - /-! ## Elliptic curves -/ -/-- An elliptic curve over a commutative ring. Note that this definition is only mathematically +-- TODO: change to `protected abbrev IsElliptic := IsUnit W.Δ` once #17458 is merged +/-- `WeierstrassCurve.IsElliptic` is a typeclass which asserts that a Weierstrass curve is an +elliptic curve: that its discriminant is a unit. Note that this definition is only mathematically accurate for certain rings whose Picard group has trivial 12-torsion, such as a field or a PID. -/ -structure EllipticCurve (R : Type u) [CommRing R] extends WeierstrassCurve R where - /-- The discriminant `Δ'` of an elliptic curve over `R`, which is given as a unit in `R`. -/ - Δ' : Rˣ - /-- The discriminant of `E` is equal to the discriminant of `E` as a Weierstrass curve. -/ - coe_Δ' : Δ' = toWeierstrassCurve.Δ +@[mk_iff] +protected class IsElliptic : Prop where + isUnit : IsUnit W.Δ -namespace EllipticCurve +variable [W.IsElliptic] -variable {R : Type u} [CommRing R] +lemma isUnit_Δ : IsUnit W.Δ := IsElliptic.isUnit -theorem toWeierstrassCurve_injective : Function.Injective (toWeierstrassCurve (R := R)) - | ⟨x1, _, x3⟩, ⟨y1, _, y3⟩, h => by - change x1 = y1 at h - congr - exact Units.ext (by rw [x3, y3, h]) +/-- The discriminant `Δ'` of an elliptic curve over `R`, which is given as a unit in `R`. +Note that to prove two equal elliptic curves have the same `Δ'`, you need to use `simp_rw`, +as `rw` cannot transfer instance `WeierstrassCurve.IsElliptic` automatically. -/ +noncomputable def Δ' : Rˣ := W.isUnit_Δ.unit -@[ext] -theorem ext {x y : EllipticCurve R} (h₁ : x.a₁ = y.a₁) (h₂ : x.a₂ = y.a₂) (h₃ : x.a₃ = y.a₃) - (h₄ : x.a₄ = y.a₄) (h₆ : x.a₆ = y.a₆) : x = y := - toWeierstrassCurve_injective (WeierstrassCurve.ext h₁ h₂ h₃ h₄ h₆) - -variable (E : EllipticCurve R) +/-- The discriminant `Δ'` of an elliptic curve is equal to the +discriminant `Δ` of it as a Weierstrass curve. -/ +@[simp] +lemma coe_Δ' : W.Δ' = W.Δ := rfl -/-- The j-invariant `j` of an elliptic curve, which is invariant under isomorphisms over `R`. -/ -def j : R := - E.Δ'⁻¹ * E.c₄ ^ 3 +/-- The j-invariant `j` of an elliptic curve, which is invariant under isomorphisms over `R`. +Note that to prove two equal elliptic curves have the same `j`, you need to use `simp_rw`, +as `rw` cannot transfer instance `WeierstrassCurve.IsElliptic` automatically. -/ +noncomputable def j : R := + W.Δ'⁻¹ * W.c₄ ^ 3 -/-- A variant of `EllipticCurve.j_eq_zero_iff` without assuming a reduced ring. -/ -lemma j_eq_zero_iff' : E.j = 0 ↔ E.c₄ ^ 3 = 0 := by +/-- A variant of `WeierstrassCurve.j_eq_zero_iff` without assuming a reduced ring. -/ +lemma j_eq_zero_iff' : W.j = 0 ↔ W.c₄ ^ 3 = 0 := by rw [j, Units.mul_right_eq_zero] -lemma j_eq_zero (h : E.c₄ = 0) : E.j = 0 := by +lemma j_eq_zero (h : W.c₄ = 0) : W.j = 0 := by rw [j_eq_zero_iff', h, zero_pow three_ne_zero] -lemma j_eq_zero_iff [IsReduced R] : E.j = 0 ↔ E.c₄ = 0 := by +lemma j_eq_zero_iff [IsReduced R] : W.j = 0 ↔ W.c₄ = 0 := by rw [j_eq_zero_iff', IsReduced.pow_eq_zero_iff three_ne_zero] section CharTwo variable [CharP R 2] -lemma j_of_char_two : E.j = E.Δ'⁻¹ * E.a₁ ^ 12 := by - rw [j, E.c₄_of_char_two, ← pow_mul] +lemma j_of_char_two : W.j = W.Δ'⁻¹ * W.a₁ ^ 12 := by + rw [j, W.c₄_of_char_two, ← pow_mul] -/-- A variant of `EllipticCurve.j_eq_zero_iff_of_char_two` without assuming a reduced ring. -/ -lemma j_eq_zero_iff_of_char_two' : E.j = 0 ↔ E.a₁ ^ 12 = 0 := by +/-- A variant of `WeierstrassCurve.j_eq_zero_iff_of_char_two` without assuming a reduced ring. -/ +lemma j_eq_zero_iff_of_char_two' : W.j = 0 ↔ W.a₁ ^ 12 = 0 := by rw [j_of_char_two, Units.mul_right_eq_zero] -lemma j_eq_zero_of_char_two (h : E.a₁ = 0) : E.j = 0 := by +lemma j_eq_zero_of_char_two (h : W.a₁ = 0) : W.j = 0 := by rw [j_eq_zero_iff_of_char_two', h, zero_pow (Nat.succ_ne_zero _)] -lemma j_eq_zero_iff_of_char_two [IsReduced R] : E.j = 0 ↔ E.a₁ = 0 := by +lemma j_eq_zero_iff_of_char_two [IsReduced R] : W.j = 0 ↔ W.a₁ = 0 := by rw [j_eq_zero_iff_of_char_two', IsReduced.pow_eq_zero_iff (Nat.succ_ne_zero _)] end CharTwo @@ -469,24 +414,26 @@ section CharThree variable [CharP R 3] -lemma j_of_char_three : E.j = E.Δ'⁻¹ * E.b₂ ^ 6 := by - rw [j, E.c₄_of_char_three, ← pow_mul] +lemma j_of_char_three : W.j = W.Δ'⁻¹ * W.b₂ ^ 6 := by + rw [j, W.c₄_of_char_three, ← pow_mul] -/-- A variant of `EllipticCurve.j_eq_zero_iff_of_char_three` without assuming a reduced ring. -/ -lemma j_eq_zero_iff_of_char_three' : E.j = 0 ↔ E.b₂ ^ 6 = 0 := by +/-- A variant of `WeierstrassCurve.j_eq_zero_iff_of_char_three` without assuming a reduced ring. -/ +lemma j_eq_zero_iff_of_char_three' : W.j = 0 ↔ W.b₂ ^ 6 = 0 := by rw [j_of_char_three, Units.mul_right_eq_zero] -lemma j_eq_zero_of_char_three (h : E.b₂ = 0) : E.j = 0 := by +lemma j_eq_zero_of_char_three (h : W.b₂ = 0) : W.j = 0 := by rw [j_eq_zero_iff_of_char_three', h, zero_pow (Nat.succ_ne_zero _)] -lemma j_eq_zero_iff_of_char_three [IsReduced R] : E.j = 0 ↔ E.b₂ = 0 := by +lemma j_eq_zero_iff_of_char_three [IsReduced R] : W.j = 0 ↔ W.b₂ = 0 := by rw [j_eq_zero_iff_of_char_three', IsReduced.pow_eq_zero_iff (Nat.succ_ne_zero _)] end CharThree -lemma twoTorsionPolynomial_disc_ne_zero [Nontrivial R] [Invertible (2 : R)] : - E.twoTorsionPolynomial.disc ≠ 0 := - E.toWeierstrassCurve.twoTorsionPolynomial_disc_ne_zero <| E.coe_Δ' ▸ E.Δ'.isUnit +-- TODO: this is defeq to `twoTorsionPolynomial_disc_ne_zero` once #17458 is merged, +-- TODO: consider removing/rephrasing this result +lemma twoTorsionPolynomial_disc_ne_zero_of_isElliptic [Nontrivial R] (hu : IsUnit (2 : R)) : + W.twoTorsionPolynomial.disc ≠ 0 := + W.twoTorsionPolynomial_disc_ne_zero hu W.isUnit_Δ section BaseChange @@ -494,155 +441,31 @@ section BaseChange variable {A : Type v} [CommRing A] (φ : R →+* A) --- Porting note: was just `@[simps]` -/-- The elliptic curve mapped over a ring homomorphism `φ : R →+* A`. -/ -@[simps (config := { rhsMd := .default }) a₁ a₂ a₃ a₄ a₆ Δ' toWeierstrassCurve] -def map : EllipticCurve A := - ⟨E.toWeierstrassCurve.map φ, Units.map φ E.Δ', by simp only [Units.coe_map, coe_Δ', E.map_Δ]; rfl⟩ - -variable (A) +instance : (W.map φ).IsElliptic := by + simp only [isElliptic_iff, map_Δ, W.isUnit_Δ.map] -/-- The elliptic curve base changed to an algebra `A` over `R`. -/ -abbrev baseChange [Algebra R A] : EllipticCurve A := - E.map <| algebraMap R A +set_option linter.docPrime false in +lemma coe_map_Δ' : (W.map φ).Δ' = φ W.Δ' := by + rw [coe_Δ', map_Δ, coe_Δ'] -variable {A} +set_option linter.docPrime false in +@[simp] +lemma map_Δ' : (W.map φ).Δ' = Units.map φ W.Δ' := by + ext + exact W.coe_map_Δ' φ -lemma coe_map_Δ' : (E.map φ).Δ' = φ E.Δ' := - rfl +set_option linter.docPrime false in +lemma coe_inv_map_Δ' : (W.map φ).Δ'⁻¹ = φ ↑W.Δ'⁻¹ := by + simp -lemma coe_inv_map_Δ' : (E.map φ).Δ'⁻¹ = φ ↑E.Δ'⁻¹ := - rfl +set_option linter.docPrime false in +lemma inv_map_Δ' : (W.map φ).Δ'⁻¹ = Units.map φ W.Δ'⁻¹ := by + simp @[simp] -lemma map_j : (E.map φ).j = φ E.j := by - simp [j, map, E.map_c₄] - -lemma map_injective {φ : R →+* A} (hφ : Function.Injective φ) : - Function.Injective <| map (φ := φ) := fun _ _ h => by - rcases mk.inj h with ⟨h1, _⟩ - rcases WeierstrassCurve.mk.inj h1 with ⟨_, _, _, _, _⟩ - ext <;> apply_fun _ using hφ <;> assumption +lemma map_j : (W.map φ).j = φ W.j := by + rw [j, coe_inv_map_Δ', map_c₄, j, map_mul, map_pow] end BaseChange -section ModelsWithJ - -/-! ### Models with prescribed j-invariant -/ - -variable (R) - -/-- When 3 is invertible, $Y^2 + Y = X^3$ is an elliptic curve. -It is of j-invariant 0 (see `EllipticCurve.ofJ0_j`). -/ -def ofJ0 [Invertible (3 : R)] : EllipticCurve R := - have := invertibleNeg (3 ^ 3 : R) - ⟨WeierstrassCurve.ofJ0 R, unitOfInvertible (-3 ^ 3 : R), - by rw [val_unitOfInvertible, WeierstrassCurve.ofJ0_Δ R]; norm_num1⟩ - -lemma ofJ0_j [Invertible (3 : R)] : (ofJ0 R).j = 0 := by - simp only [j, ofJ0, WeierstrassCurve.ofJ0_c₄] - ring1 - -/-- When 2 is invertible, $Y^2 = X^3 + X$ is an elliptic curve. -It is of j-invariant 1728 (see `EllipticCurve.ofJ1728_j`). -/ -def ofJ1728 [Invertible (2 : R)] : EllipticCurve R := - have := invertibleNeg (2 ^ 6 : R) - ⟨WeierstrassCurve.ofJ1728 R, unitOfInvertible (-2 ^ 6 : R), - by rw [val_unitOfInvertible, WeierstrassCurve.ofJ1728_Δ R]; norm_num1⟩ - -lemma ofJ1728_j [Invertible (2 : R)] : (ofJ1728 R).j = 1728 := by - field_simp [j, ofJ1728, @val_unitOfInvertible _ _ _ <| invertibleNeg _, - WeierstrassCurve.ofJ1728_c₄] - norm_num1 - -variable {R} - -/-- When j and j - 1728 are both invertible, -$Y^2 + (j - 1728)XY = X^3 - 36(j - 1728)^3X - (j - 1728)^5$ is an elliptic curve. -It is of j-invariant j (see `EllipticCurve.ofJ'_j`). -/ -def ofJ' (j : R) [Invertible j] [Invertible (j - 1728)] : EllipticCurve R := - have := invertibleMul (j ^ 2) ((j - 1728) ^ 9) - ⟨WeierstrassCurve.ofJ j, unitOfInvertible <| j ^ 2 * (j - 1728) ^ 9, - (WeierstrassCurve.ofJ_Δ j).symm⟩ - -lemma ofJ'_j (j : R) [Invertible j] [Invertible (j - 1728)] : (ofJ' j).j = j := by - field_simp [EllipticCurve.j, ofJ', @val_unitOfInvertible _ _ _ <| invertibleMul .., - WeierstrassCurve.ofJ_c₄] - ring1 - -variable {F : Type u} [Field F] (j : F) - -private lemma two_or_three_ne_zero : (2 : F) ≠ 0 ∨ (3 : F) ≠ 0 := - ne_zero_or_ne_zero_of_nat_coprime <| by decide - -variable [DecidableEq F] - -/-- For any element j of a field $F$, there exists an elliptic curve over $F$ -with j-invariant equal to j (see `EllipticCurve.ofJ_j`). -Its coefficients are given explicitly (see `EllipticCurve.ofJ0`, `EllipticCurve.ofJ1728` -and `EllipticCurve.ofJ'`). -/ -def ofJ : EllipticCurve F := - if h0 : j = 0 then - if h3 : (3 : F) = 0 then @ofJ1728 _ _ <| invertibleOfNonzero <| - two_or_three_ne_zero.neg_resolve_right h3 - else @ofJ0 _ _ <| invertibleOfNonzero h3 - else if h1728 : j = 1728 then - @ofJ1728 _ _ <| invertibleOfNonzero fun h => h0 <| - by rw [h1728, show (1728 : F) = 2 * 864 by norm_num1, h, zero_mul] - else @ofJ' _ _ j (invertibleOfNonzero h0) (invertibleOfNonzero <| sub_ne_zero_of_ne h1728) - -lemma ofJ_0_of_three_ne_zero [h3 : NeZero (3 : F)] : - ofJ 0 = @ofJ0 _ _ (invertibleOfNonzero h3.out) := by - rw [ofJ, dif_pos rfl, dif_neg h3.out] - -lemma ofJ_0_of_three_eq_zero (h3 : (3 : F) = 0) : - ofJ 0 = @ofJ1728 _ _ (invertibleOfNonzero <| two_or_three_ne_zero.neg_resolve_right h3) := by - rw [ofJ, dif_pos rfl, dif_pos h3] - -lemma ofJ_0_of_two_eq_zero (h2 : (2 : F) = 0) : - ofJ 0 = @ofJ0 _ _ (invertibleOfNonzero <| two_or_three_ne_zero.neg_resolve_left h2) := - have := neZero_iff.2 <| two_or_three_ne_zero.neg_resolve_left h2 - ofJ_0_of_three_ne_zero - -lemma ofJ_1728_of_three_eq_zero (h3 : (3 : F) = 0) : - ofJ 1728 = @ofJ1728 _ _ (invertibleOfNonzero <| two_or_three_ne_zero.neg_resolve_right h3) := by - rw [ofJ, dif_pos <| by rw [show (1728 : F) = 3 * 576 by norm_num1, h3, zero_mul], dif_pos h3] - -lemma ofJ_1728_of_two_ne_zero [h2 : NeZero (2 : F)] : - ofJ 1728 = @ofJ1728 _ _ (invertibleOfNonzero h2.out) := by - by_cases h3 : (3 : F) = 0 - · exact ofJ_1728_of_three_eq_zero h3 - · have h : (1728 : F) ≠ 0 := fun h => or_iff_not_and_not.mp - (mul_eq_zero.mp <| by rwa [show 2 ^ 6 * 3 ^ 3 = (1728 : F) by norm_num1]) - ⟨pow_ne_zero 6 h2.out, pow_ne_zero 3 h3⟩ - rw [ofJ, dif_neg h, dif_pos rfl] - -lemma ofJ_1728_of_two_eq_zero (h2 : (2 : F) = 0) : - ofJ 1728 = @ofJ0 _ _ (invertibleOfNonzero <| two_or_three_ne_zero.neg_resolve_left h2) := by - rw [ofJ, dif_pos <| by rw [show (1728 : F) = 2 * 864 by norm_num1, h2, zero_mul], dif_neg] - -lemma ofJ_ne_0_ne_1728 (h0 : j ≠ 0) (h1728 : j ≠ 1728) : ofJ j = - @ofJ' _ _ j (invertibleOfNonzero h0) (invertibleOfNonzero <| sub_ne_zero_of_ne h1728) := by - rw [ofJ, dif_neg h0, dif_neg h1728] - -lemma ofJ_j : (ofJ j).j = j := by - by_cases h0 : j = 0 - · by_cases h3 : (3 : F) = 0 - · rw [h0, ofJ_0_of_three_eq_zero h3, - @ofJ1728_j _ _ <| invertibleOfNonzero <| two_or_three_ne_zero.neg_resolve_right h3, - show (1728 : F) = 3 * 576 by norm_num1, h3, zero_mul] - · rw [h0, ofJ_0_of_three_ne_zero (h3 := neZero_iff.2 h3), @ofJ0_j _ _ <| invertibleOfNonzero h3] - · by_cases h1728 : j = 1728 - · have h2 : (2 : F) ≠ 0 := - fun h => h0 <| by rw [h1728, show (1728 : F) = 2 * 864 by norm_num1, h, zero_mul] - rw [h1728, ofJ_1728_of_two_ne_zero (h2 := neZero_iff.2 h2), - @ofJ1728_j _ _ <| invertibleOfNonzero h2] - · rw [ofJ_ne_0_ne_1728 j h0 h1728, - @ofJ'_j _ _ _ (invertibleOfNonzero h0) (invertibleOfNonzero <| sub_ne_zero_of_ne h1728)] - -instance instInhabitedEllipticCurve : Inhabited <| EllipticCurve F := - ⟨ofJ 37⟩ - -end ModelsWithJ - -end EllipticCurve +end WeierstrassCurve diff --git a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean index 12264f5de8c43..763031d694da3 100644 --- a/Mathlib/AlgebraicGeometry/Modules/Tilde.lean +++ b/Mathlib/AlgebraicGeometry/Modules/Tilde.lean @@ -158,7 +158,11 @@ noncomputable instance (U : (Opens (PrimeSpectrum.Top R))ᵒᵖ) : noncomputable def tilde : (Spec (CommRingCat.of R)).Modules where val := { obj := fun U ↦ ModuleCat.of _ (M.tildeInType.val.obj U) - map := fun {U V} i ↦ + map := fun {U V} i ↦ ofHom + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)` + -- This suggests `restrictScalars` needs to be redesigned. + (Y := (restrictScalars ((Spec (CommRingCat.of R)).ringCatSheaf.val.map i)).obj + (of ((Spec (CommRingCat.of R)).ringCatSheaf.val.obj V) (M.tildeInType.val.obj V))) { toFun := M.tildeInType.val.map i map_smul' := by intros; rfl map_add' := by intros; rfl } } @@ -200,15 +204,18 @@ If `U` is an open subset of `Spec R`, this is the morphism of `R`-modules from ` `M^~(U)`. -/ def toOpen (U : Opens (PrimeSpectrum.Top R)) : - ModuleCat.of R M ⟶ (tildeInModuleCat M).1.obj (op U) where - toFun f := - ⟨fun x ↦ LocalizedModule.mkLinearMap _ _ f, fun x ↦ - ⟨U, x.2, 𝟙 _, f, 1, fun y ↦ ⟨(Ideal.ne_top_iff_one _).1 y.1.2.1, by simp⟩⟩⟩ - map_add' f g := Subtype.eq <| funext fun x ↦ LinearMap.map_add _ _ _ - map_smul' r m := by - simp only [isLocallyFraction_pred, LocalizedModule.mkLinearMap_apply, LinearMapClass.map_smul, - RingHom.id_apply] - rfl + ModuleCat.of R M ⟶ (tildeInModuleCat M).1.obj (op U) := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(Y := ...)` + -- This suggests `restrictScalars` needs to be redesigned. + ModuleCat.ofHom (Y := (tildeInModuleCat M).1.obj (op U)) + { toFun := fun f => + ⟨fun x ↦ LocalizedModule.mkLinearMap _ _ f, fun x ↦ + ⟨U, x.2, 𝟙 _, f, 1, fun y ↦ ⟨(Ideal.ne_top_iff_one _).1 y.1.2.1, by simp⟩⟩⟩ + map_add' := fun f g => Subtype.eq <| funext fun x ↦ LinearMap.map_add _ _ _ + map_smul' := fun r m => by + simp only [isLocallyFraction_pred, LocalizedModule.mkLinearMap_apply, LinearMapClass.map_smul, + RingHom.id_apply] + rfl } @[simp] theorem toOpen_res (U V : Opens (PrimeSpectrum.Top R)) (i : V ⟶ U) : @@ -235,7 +242,8 @@ lemma isUnit_toStalk (x : PrimeSpectrum.Top R) (r : x.asIdeal.primeCompl) : ⟨fun q ↦ (Localization.mk 1 ⟨r, q.2.2⟩ : Localization.AtPrime q.1.asIdeal) • s.1 ⟨q.1, q.2.1⟩, fun q ↦ ?_⟩, by simpa only [Module.algebraMap_end_apply, ← map_smul] using - germ_ext (W := O) (hxW := ⟨mem, r.2⟩) (iWU := 𝟙 _) (iWV := homOfLE inf_le_left) _ <| + germ_ext (C := ModuleCat R) (W := O) (hxW := ⟨mem, r.2⟩) (iWU := 𝟙 _) + (iWV := homOfLE inf_le_left) _ <| Subtype.eq <| funext fun y ↦ smul_eq_iff_of_mem (S := y.1.1.primeCompl) r _ _ _ |>.2 rfl⟩ obtain ⟨V, mem_V, iV, num, den, hV⟩ := s.2 ⟨q.1, q.2.1⟩ refine ⟨V ⊓ O, ⟨mem_V, q.2⟩, homOfLE inf_le_right, num, r * den, fun y ↦ ?_⟩ @@ -252,7 +260,7 @@ to the stalk of `M^~` at `x`. noncomputable def localizationToStalk (x : PrimeSpectrum.Top R) : ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) ⟶ (TopCat.Presheaf.stalk (tildeInModuleCat M) x) := - LocalizedModule.lift _ (toStalk M x) <| isUnit_toStalk M x + ModuleCat.ofHom <| LocalizedModule.lift _ (toStalk M x).hom <| isUnit_toStalk M x /-- The ring homomorphism that takes a section of the structure sheaf of `R` on the open set `U`, @@ -260,10 +268,15 @@ implemented as a subtype of dependent functions to localizations at prime ideals the section on the point corresponding to a given prime ideal. -/ def openToLocalization (U : Opens (PrimeSpectrum R)) (x : PrimeSpectrum R) (hx : x ∈ U) : (tildeInModuleCat M).obj (op U) ⟶ - ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) where - toFun s := (s.1 ⟨x, hx⟩ : _) - map_add' _ _ := rfl - map_smul' _ _ := rfl + ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) := + -- TODO: after https://github.com/leanprover-community/mathlib4/pull/19511 we need to hint `(X := ...)` and `(Y := ...)` + -- This suggests `restrictScalars` needs to be redesigned. + ModuleCat.ofHom + (X := (tildeInModuleCat M).obj (op U)) + (Y := ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M)) + { toFun := fun s => (s.1 ⟨x, hx⟩ : _) + map_add' := fun _ _ => rfl + map_smul' := fun _ _ => rfl } /-- The morphism of `R`-modules from the stalk of `M^~` at `x` to the localization of `M` at the @@ -286,9 +299,9 @@ theorem germ_comp_stalkToFiberLinearMap (U : Opens (PrimeSpectrum.Top R)) (x) (h @[simp] theorem stalkToFiberLinearMap_germ (U : Opens (PrimeSpectrum.Top R)) (x : PrimeSpectrum.Top R) (hx : x ∈ U) (s : (tildeInModuleCat M).1.obj (op U)) : - stalkToFiberLinearMap M x + (stalkToFiberLinearMap M x).hom (TopCat.Presheaf.germ (tildeInModuleCat M) U x hx s) = (s.1 ⟨x, hx⟩ : _) := - DFunLike.ext_iff.1 (germ_comp_stalkToFiberLinearMap M U x hx) s + DFunLike.ext_iff.1 (ModuleCat.hom_ext_iff.mp (germ_comp_stalkToFiberLinearMap M U x hx)) s @[reassoc (attr := simp), elementwise (attr := simp)] theorem toOpen_germ (U : Opens (PrimeSpectrum.Top R)) (x) (hx : x ∈ U) : @@ -298,13 +311,13 @@ theorem toOpen_germ (U : Opens (PrimeSpectrum.Top R)) (x) (hx : x ∈ U) : @[reassoc (attr := simp)] theorem toStalk_comp_stalkToFiberLinearMap (x : PrimeSpectrum.Top R) : toStalk M x ≫ stalkToFiberLinearMap M x = - LocalizedModule.mkLinearMap x.asIdeal.primeCompl M := by + ofHom (LocalizedModule.mkLinearMap x.asIdeal.primeCompl M) := by rw [toStalk, Category.assoc, germ_comp_stalkToFiberLinearMap]; rfl theorem stalkToFiberLinearMap_toStalk (x : PrimeSpectrum.Top R) (m : M) : - (stalkToFiberLinearMap M x) (toStalk M x m) = + (stalkToFiberLinearMap M x).hom (toStalk M x m) = LocalizedModule.mk m 1 := - LinearMap.ext_iff.1 (toStalk_comp_stalkToFiberLinearMap M x) _ + LinearMap.ext_iff.1 (ModuleCat.hom_ext_iff.mp (toStalk_comp_stalkToFiberLinearMap M x)) _ /-- If `U` is an open subset of `Spec R`, `m` is an element of `M` and `r` is an element of `R` @@ -347,7 +360,7 @@ theorem res_const (f : M) (g : R) (U hu V hv i) : @[simp] theorem localizationToStalk_mk (x : PrimeSpectrum.Top R) (f : M) (s : x.asIdeal.primeCompl) : - localizationToStalk M x (LocalizedModule.mk f s) = + (localizationToStalk M x).hom (LocalizedModule.mk f s) = (tildeInModuleCat M).germ (PrimeSpectrum.basicOpen (s : R)) x s.2 (const M f s (PrimeSpectrum.basicOpen s) fun _ => id) := (Module.End_isUnit_iff _ |>.1 (isUnit_toStalk M x s)).injective <| by @@ -356,6 +369,7 @@ theorem localizationToStalk_mk (x : PrimeSpectrum.Top R) (f : M) (s : x.asIdeal. show (M.tildeInModuleCat.germ ⊤ x ⟨⟩) ((toOpen M ⊤) f) = _ rw [← map_smul] fapply TopCat.Presheaf.germ_ext (W := PrimeSpectrum.basicOpen s.1) (hxW := s.2) + (F := M.tildeInModuleCat) · exact homOfLE le_top · exact 𝟙 _ refine Subtype.eq <| funext fun y => show LocalizedModule.mk f 1 = _ from ?_ @@ -376,7 +390,8 @@ noncomputable def stalkIso (x : PrimeSpectrum.Top R) : ModuleCat.of R (LocalizedModule x.asIdeal.primeCompl M) where hom := stalkToFiberLinearMap M x inv := localizationToStalk M x - hom_inv_id := TopCat.Presheaf.stalk_hom_ext _ fun U hxU ↦ ext _ fun s ↦ by + hom_inv_id := TopCat.Presheaf.stalk_hom_ext _ fun U hxU ↦ ModuleCat.hom_ext <| + LinearMap.ext fun s ↦ by show localizationToStalk M x (stalkToFiberLinearMap M x (M.tildeInModuleCat.germ U x hxU s)) = M.tildeInModuleCat.germ U x hxU s rw [stalkToFiberLinearMap_germ] @@ -384,15 +399,19 @@ noncomputable def stalkIso (x : PrimeSpectrum.Top R) : exists_const _ _ s x hxU rw [← res_apply M U V iVU s ⟨x, hxV⟩, ← hs, const_apply, localizationToStalk_mk] exact (tildeInModuleCat M).germ_ext V hxV (homOfLE hg) iVU <| hs ▸ rfl - inv_hom_id := by ext x; exact x.induction_on (fun _ _ => by simp) + inv_hom_id := by ext x; exact x.induction_on (fun _ _ => by + simp only [hom_comp, LinearMap.coe_comp, Function.comp_apply, hom_id, LinearMap.id_coe, id_eq] + rw [localizationToStalk_mk, stalkToFiberLinearMap_germ] + simp) instance (x : PrimeSpectrum.Top R) : - IsLocalizedModule x.asIdeal.primeCompl (toStalk M x) := by + IsLocalizedModule x.asIdeal.primeCompl (toStalk M x).hom := by convert IsLocalizedModule.of_linearEquiv (hf := localizedModuleIsLocalizedModule (M := M) x.asIdeal.primeCompl) (e := (stalkIso M x).symm.toLinearEquiv) - simp only [of_coe, show (stalkIso M x).symm.toLinearEquiv.toLinearMap = (stalkIso M x).inv by rfl, - stalkIso_inv] + ext + simp only [of_coe, + show (stalkIso M x).symm.toLinearEquiv.toLinearMap = (stalkIso M x).inv.hom by rfl] erw [LocalizedModule.lift_comp] end Tilde diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean index 18ec910454728..a44c42830da74 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiCompact.lean @@ -116,7 +116,6 @@ theorem isCompact_basicOpen (X : Scheme) {U : X.Opens} (hU : IsCompact (U : Set refine Set.Subset.trans ?_ (Set.subset_iUnion₂ j hj) exact Set.Subset.rfl -@[reducible] instance : HasAffineProperty @QuasiCompact (fun X _ _ _ ↦ CompactSpace X) where eq_targetAffineLocally' := by ext X Y f diff --git a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean index a7b0a7bbd4948..19388a0c54fbd 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/QuasiSeparated.lean @@ -107,7 +107,6 @@ theorem quasiCompact_affineProperty_iff_quasiSeparatedSpace {X Y : Scheme} [IsAf theorem quasiSeparated_eq_diagonal_is_quasiCompact : @QuasiSeparated = MorphismProperty.diagonal @QuasiCompact := by ext; exact quasiSeparated_iff _ -@[reducible] instance : HasAffineProperty @QuasiSeparated (fun X _ _ _ ↦ QuasiSeparatedSpace X) where __ := HasAffineProperty.copy quasiSeparated_eq_diagonal_is_quasiCompact.symm diff --git a/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean index 66aff1bb5a74d..31a833ebabe90 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/SurjectiveOnStalks.lean @@ -113,10 +113,12 @@ lemma isEmbedding_pullback {X Y S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) [Sur obtain ⟨x, rfl⟩ := (Scheme.homeoOfIso (pullbackSpecIso R A B).symm).surjective x simp only [Scheme.homeoOfIso_apply, Function.comp_apply] ext - · simp only [← Scheme.comp_base_apply, pullback.lift_fst, Iso.symm_hom, Iso.inv_hom_id] + · simp only [L, ← Scheme.comp_base_apply, pullback.lift_fst, Iso.symm_hom, + Iso.inv_hom_id] erw [← Scheme.comp_base_apply, pullbackSpecIso_inv_fst_assoc] rfl - · simp only [← Scheme.comp_base_apply, pullback.lift_snd, Iso.symm_hom, Iso.inv_hom_id] + · simp only [L, ← Scheme.comp_base_apply, pullback.lift_snd, Iso.symm_hom, + Iso.inv_hom_id] erw [← Scheme.comp_base_apply, pullbackSpecIso_inv_snd_assoc] rfl let 𝒰 := S.affineOpenCover.openCover @@ -178,7 +180,8 @@ lemma isEmbedding_pullback {X Y S : Scheme.{u}} (f : X ⟶ S) (g : Y ⟶ S) [Sur inferInstance inferInstance inferInstance convert this using 6 apply pullback.hom_ext <;> - simp [𝓤, ← pullback.condition, ← pullback.condition_assoc, Scheme.Cover.pullbackHom] + simp [𝓤, ← pullback.condition, ← pullback.condition_assoc, + Scheme.Cover.pullbackHom] end SurjectiveOnStalks diff --git a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean index 84a2cb83d773a..d8cdaa1f4dd0a 100644 --- a/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean +++ b/Mathlib/AlgebraicGeometry/Morphisms/UniversallyClosed.lean @@ -135,7 +135,7 @@ lemma compactSpace_of_universallyClosed contrapose! h obtain ⟨x, hx⟩ := h obtain ⟨z, rfl, hzr⟩ := exists_preimage_pullback x t' (Subsingleton.elim (f.base x) (q.base t')) - suffices ∀ i, t ∈ (Ti i).comap (comap φ) → p.base z ∉ U i from ⟨z, by simpa [Z, p, hzr], hzr⟩ + suffices ∀ i, t ∈ (Ti i).comap (comap φ) → p.base z ∉ U i from ⟨z, by simpa [Z, p, fT, hzr], hzr⟩ intro i hi₁ hi₂ rw [comap_basicOpen, show φ (.X i) = 0 by simpa [φ] using (hx i · hi₂), basicOpen_zero] at hi₁ cases hi₁ diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean index bb1699add44f8..a209d03a31d28 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Basic.lean @@ -10,6 +10,7 @@ import Mathlib.RingTheory.KrullDimension.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Defs import Mathlib.RingTheory.LocalRing.RingHom.Basic import Mathlib.RingTheory.Localization.Away.Basic +import Mathlib.RingTheory.MaximalSpectrum import Mathlib.Tactic.StacksAttribute import Mathlib.Topology.KrullDimension import Mathlib.Topology.Sober @@ -237,6 +238,12 @@ theorem discreteTopology_iff_finite_isMaximal_and_sInf_le_nilradical : rwa [← hM.eq_of_le hI.1 hMI] exact ⟨fin.subset hpm, hpm⟩ +theorem discreteTopology_of_toLocalization_surjective + (surj : Function.Surjective (toPiLocalization R)) : + DiscreteTopology (PrimeSpectrum R) := + discreteTopology_iff_finite_and_isPrime_imp_isMaximal.mpr ⟨finite_of_toPiLocalization_surjective + surj, fun I prime ↦ isMaximal_of_toPiLocalization_surjective surj ⟨I, prime⟩⟩ + section Comap variable {S' : Type*} [CommSemiring S'] @@ -542,11 +549,14 @@ theorem isLocalization_away_iff_atPrime_of_basicOpen_eq_singleton [Algebra R S] exact not_not.mpr (q.span_singleton_le_iff_mem.mp le) IsLocalization.isLocalization_iff_of_isLocalization _ _ (Localization.Away f) -variable [DiscreteTopology (PrimeSpectrum R)] +end BasicOpen -variable (R) in -lemma _root_.RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology : - Function.Surjective (RingHom.toLocalizationIsMaximal R) := fun x ↦ by +section DiscreteTopology + +variable (R) [DiscreteTopology (PrimeSpectrum R)] + +theorem toPiLocalization_surjective_of_discreteTopology : + Function.Surjective (toPiLocalization R) := fun x ↦ by have (p : PrimeSpectrum R) : ∃ f, (basicOpen f : Set _) = {p} := have ⟨_, ⟨f, rfl⟩, hpf, hfp⟩ := isTopologicalBasis_basic_opens.isOpen_iff.mp (isOpen_discrete {p}) p rfl @@ -555,16 +565,15 @@ lemma _root_.RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology : let e := Equiv.ofInjective f fun p q eq ↦ Set.singleton_injective (hf p ▸ eq ▸ hf q) have loc a : IsLocalization.AtPrime (Localization.Away a.1) (e.symm a).1 := (isLocalization_away_iff_atPrime_of_basicOpen_eq_singleton <| hf _).mp <| by - simp_rw [Equiv.apply_ofInjective_symm]; infer_instance + simp_rw [e, Equiv.apply_ofInjective_symm]; infer_instance let algE a := IsLocalization.algEquiv (e.symm a).1.primeCompl (Localization.AtPrime (e.symm a).1) (Localization.Away a.1) have span_eq : Ideal.span (Set.range f) = ⊤ := iSup_basicOpen_eq_top_iff.mp <| top_unique fun p _ ↦ TopologicalSpace.Opens.mem_iSup.mpr ⟨p, (hf p).ge rfl⟩ replace hf a : (basicOpen a.1 : Set _) = {e.symm a} := by - simp_rw [← hf, Equiv.apply_ofInjective_symm] - have := (discreteTopology_iff_finite_and_isPrime_imp_isMaximal.mp ‹_›).2 + simp_rw [e, ← hf, Equiv.apply_ofInjective_symm] obtain ⟨r, eq, -⟩ := Localization.existsUnique_algebraMap_eq_of_span_eq_top _ span_eq - (fun a ↦ algE a (x ⟨_, this _ inferInstance⟩)) fun a b ↦ by + (fun a ↦ algE a (x _)) fun a b ↦ by obtain rfl | ne := eq_or_ne a b; · rfl have ⟨n, hn⟩ : IsNilpotent (a * b : R) := (basicOpen_eq_bot_iff _).mp <| by simp_rw [basicOpen_mul, SetLike.ext'_iff, TopologicalSpace.Opens.coe_inf, hf] @@ -573,19 +582,35 @@ lemma _root_.RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology : (S := Localization.Away (a * b : R)) <| hn ▸ ⟨n, rfl⟩ apply Subsingleton.elim refine ⟨r, funext fun I ↦ ?_⟩ - have := eq (e ⟨I, I.2.isPrime⟩) + have := eq (e I) rwa [← AlgEquiv.symm_apply_eq, AlgEquiv.commutes, e.symm_apply_apply] at this +theorem maximalSpectrumToPiLocalization_surjective_of_discreteTopology : + Function.Surjective (MaximalSpectrum.toPiLocalization R) := by + rw [← piLocalizationToMaximal_comp_toPiLocalization] + exact (piLocalizationToMaximal_surjective R).comp + (toPiLocalization_surjective_of_discreteTopology R) + /-- If the prime spectrum of a commutative semiring R has discrete Zariski topology, then R is canonically isomorphic to the product of its localizations at the (finitely many) maximal ideals. -/ @[stacks 00JA "See also `PrimeSpectrum.discreteTopology_iff_finite_isMaximal_and_sInf_le_nilradical`."] -def _root_.RingHom.toLocalizationIsMaximalEquiv : R ≃+* - Π I : {I : Ideal R // I.IsMaximal}, haveI : I.1.IsMaximal := I.2; Localization.AtPrime I.1 := - .ofBijective _ ⟨RingHom.toLocalizationIsMaximal_injective R, - RingHom.toLocalizationIsMaximal_surjective_of_discreteTopology R⟩ +def MaximalSpectrum.toPiLocalizationEquivtoLocalizationEquiv : + R ≃+* MaximalSpectrum.PiLocalization R := + .ofBijective _ ⟨MaximalSpectrum.toPiLocalization_injective R, + maximalSpectrumToPiLocalization_surjective_of_discreteTopology R⟩ -end BasicOpen +theorem discreteTopology_iff_toPiLocalization_surjective {R} [CommSemiring R] : + DiscreteTopology (PrimeSpectrum R) ↔ Function.Surjective (toPiLocalization R) := + ⟨fun _ ↦ toPiLocalization_surjective_of_discreteTopology _, + discreteTopology_of_toLocalization_surjective⟩ + +theorem discreteTopology_iff_toPiLocalization_bijective {R} [CommSemiring R] : + DiscreteTopology (PrimeSpectrum R) ↔ Function.Bijective (toPiLocalization R) := + discreteTopology_iff_toPiLocalization_surjective.trans + (and_iff_right <| toPiLocalization_injective _).symm + +end DiscreteTopology section Order @@ -880,7 +905,7 @@ lemma isIntegral_of_isClosedMap_comap_mapRingHom (h : IsClosedMap (comap (mapRin · have : p.natDegree ≤ 1 := by simpa using natDegree_linear_le (a := r) (b := -1) rw [eval₂_eq_eval_map, reverse, Polynomial.map_mul, ← reflect_map, Polynomial.map_pow, map_X, ← revAt_zero (1 + _), ← reflect_monomial, - ← reflect_mul _ _ (natDegree_map_le _ _) (by simp), pow_zero, mul_one, hc, + ← reflect_mul _ _ natDegree_map_le (by simp), pow_zero, mul_one, hc, ← add_assoc, reflect_mul _ _ (this.trans (by simp)) le_rfl, eval_mul, reflect_sub, reflect_mul _ _ (by simp) (by simp)] simp [← pow_succ'] diff --git a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean index 57274ae5ae060..f7cf9b2d50040 100644 --- a/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean +++ b/Mathlib/AlgebraicGeometry/PrimeSpectrum/Jacobson.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.AlgebraicGeometry.PrimeSpectrum.Noetherian -import Mathlib.RingTheory.Jacobson +import Mathlib.RingTheory.Jacobson.Ring import Mathlib.Topology.JacobsonSpace /-! diff --git a/Mathlib/AlgebraicGeometry/RationalMap.lean b/Mathlib/AlgebraicGeometry/RationalMap.lean index e9894ddfbcd61..7e848dcf6666c 100644 --- a/Mathlib/AlgebraicGeometry/RationalMap.lean +++ b/Mathlib/AlgebraicGeometry/RationalMap.lean @@ -511,8 +511,8 @@ def RationalMap.toPartialMap [IsReduced X] [Y.IsSeparated] (f : X ⤏ Y) : X.Par show _ ≫ _ ≫ (g x).hom = _ ≫ _ ≫ (g y).hom simp_rw [← cancel_epi (X.isoOfEq congr($(hg₂ x) ⊓ $(hg₂ y))).hom, ← Category.assoc] convert (PartialMap.equiv_iff_of_isSeparated (S := ⊤_ _) (f := g x) (g := g y)).mp ?_ using 1 - · dsimp; congr 1; simp [← cancel_mono (Opens.ι _)] - · dsimp; congr 1; simp [← cancel_mono (Opens.ι _)] + · dsimp; congr 1; simp [g, ← cancel_mono (Opens.ι _)] + · dsimp; congr 1; simp [g, ← cancel_mono (Opens.ι _)] · rw [← PartialMap.toRationalMap_eq_iff, hg₁, hg₁] lemma PartialMap.toPartialMap_toRationalMap_restrict [IsReduced X] [Y.IsSeparated] diff --git a/Mathlib/AlgebraicGeometry/Sites/MorphismProperty.lean b/Mathlib/AlgebraicGeometry/Sites/MorphismProperty.lean index e8684970f0fd7..84d50d0d2a13d 100644 --- a/Mathlib/AlgebraicGeometry/Sites/MorphismProperty.lean +++ b/Mathlib/AlgebraicGeometry/Sites/MorphismProperty.lean @@ -130,7 +130,7 @@ lemma grothendieckTopology_cover {X : Scheme.{u}} (𝒰 : Cover.{v} P X) : } refine ⟨_, pretopology_cover 𝒱, ?_⟩ rintro _ _ ⟨y⟩ - exact ⟨_, 𝟙 _, 𝒰.map (𝒰.f y), ⟨_⟩, by simp⟩ + exact ⟨_, 𝟙 _, 𝒰.map (𝒰.f y), ⟨_⟩, by simp [𝒱]⟩ section diff --git a/Mathlib/AlgebraicGeometry/Sites/Small.lean b/Mathlib/AlgebraicGeometry/Sites/Small.lean new file mode 100644 index 0000000000000..5e5bfcaf299da --- /dev/null +++ b/Mathlib/AlgebraicGeometry/Sites/Small.lean @@ -0,0 +1,260 @@ +/- +Copyright (c) 2024 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten +-/ +import Mathlib.AlgebraicGeometry.Cover.Over +import Mathlib.AlgebraicGeometry.Sites.MorphismProperty +import Mathlib.CategoryTheory.Sites.DenseSubsite.InducedTopology +import Mathlib.CategoryTheory.Sites.Over + +/-! +# Small sites + +In this file we define the small sites associated to morphism properties and give +generating pretopologies. + +## Main definitions + +- `AlgebraicGeometry.Scheme.overGrothendieckTopology`: the Grothendieck topology on `Over S` + obtained by localizing the topology on `Scheme` induced by `P` at `S`. +- `AlgebraicGeometry.Scheme.overPretopology`: the pretopology on `Over S` defined by + `P`-coverings of `S`-schemes. The induced topology agrees with + `AlgebraicGeometry.Scheme.overGrothendieckTopology`. +- `AlgebraicGeometry.Scheme.smallGrothendieckTopology`: the by the inclusion + `P.Over ⊤ S ⥤ Over S` induced topology on `P.Over ⊤ S`. +- `AlgebraicGeometry.Scheme.smallPretopology`: the pretopology on `P.Over ⊤ S` defined by + `P`-coverings of `S`-schemes with `P`. The induced topology agrees + with `AlgebraicGeometry.Scheme.smallGrothendieckTopology`. + +-/ + +universe v u + +open CategoryTheory Limits + +namespace AlgebraicGeometry.Scheme + +variable {P Q : MorphismProperty Scheme.{u}} {S : Scheme.{u}} + +/-- The presieve defined by a `P`-cover of `S`-schemes. -/ +def Cover.toPresieveOver {X : Over S} (𝒰 : Cover.{u} P X.left) [𝒰.Over S] : Presieve X := + Presieve.ofArrows (fun i ↦ (𝒰.obj i).asOver S) (fun i ↦ (𝒰.map i).asOver S) + +/-- The presieve defined by a `P`-cover of `S`-schemes with `Q`. -/ +def Cover.toPresieveOverProp {X : Q.Over ⊤ S} (𝒰 : Cover.{u} P X.left) [𝒰.Over S] + (h : ∀ j, Q (𝒰.obj j ↘ S)) : Presieve X := + Presieve.ofArrows (fun i ↦ (𝒰.obj i).asOverProp S (h i)) (fun i ↦ (𝒰.map i).asOverProp S) + +lemma Cover.overEquiv_generate_toPresieveOver_eq_ofArrows {X : Over S} (𝒰 : Cover.{u} P X.left) + [𝒰.Over S] : Sieve.overEquiv X (Sieve.generate 𝒰.toPresieveOver) = + Sieve.ofArrows 𝒰.obj 𝒰.map := by + ext V f + simp only [Sieve.overEquiv_iff, Functor.const_obj_obj, Sieve.generate_apply] + constructor + · rintro ⟨U, h, g, ⟨k⟩, hcomp⟩ + exact ⟨𝒰.obj k, h.left, 𝒰.map k, ⟨k⟩, congrArg CommaMorphism.left hcomp⟩ + · rintro ⟨U, h, g, ⟨k⟩, hcomp⟩ + have : 𝒰.map k ≫ X.hom = 𝒰.obj k ↘ S := comp_over (𝒰.map k) S + refine ⟨(𝒰.obj k).asOver S, Over.homMk h (by simp [← hcomp, this]), (𝒰.map k).asOver S, ⟨k⟩, ?_⟩ + ext : 1 + simpa + +lemma Cover.toPresieveOver_le_arrows_iff {X : Over S} (R : Sieve X) (𝒰 : Cover.{u} P X.left) + [𝒰.Over S] : + 𝒰.toPresieveOver ≤ R.arrows ↔ + Presieve.ofArrows 𝒰.obj 𝒰.map ≤ (Sieve.overEquiv X R).arrows := by + simp_rw [← Sieve.giGenerate.gc.le_iff_le, ← Sieve.overEquiv_le_overEquiv_iff] + rw [overEquiv_generate_toPresieveOver_eq_ofArrows] + +variable [P.IsMultiplicative] [P.RespectsIso] + [P.IsStableUnderBaseChange] [IsJointlySurjectivePreserving P] + +variable (P Q S) + +/-- The pretopology on `Over S` induced by `P` where coverings are given by `P`-covers +of `S`-schemes. -/ +def overPretopology : Pretopology (Over S) where + coverings Y R := ∃ (𝒰 : Cover.{u} P Y.left) (_ : 𝒰.Over S), R = 𝒰.toPresieveOver + has_isos {X Y} f _ := ⟨coverOfIsIso f.left, inferInstance, (Presieve.ofArrows_pUnit _).symm⟩ + pullbacks := by + rintro Y X f _ ⟨𝒰, h, rfl⟩ + refine ⟨𝒰.pullbackCoverOver' S f.left, inferInstance, ?_⟩ + simpa [Cover.toPresieveOver] using + (Presieve.ofArrows_pullback f (fun i ↦ (𝒰.obj i).asOver S) (fun i ↦ (𝒰.map i).asOver S)).symm + transitive := by + rintro X _ T ⟨𝒰, h, rfl⟩ H + choose V h hV using H + refine ⟨𝒰.bind (fun j => V ((𝒰.map j).asOver S) ⟨j⟩), inferInstance, ?_⟩ + convert Presieve.ofArrows_bind _ (fun j ↦ (𝒰.map j).asOver S) _ + (fun Y f H j ↦ ((V f H).obj j).asOver S) (fun Y f H j ↦ ((V f H).map j).asOver S) + apply hV + +/-- The topology on `Over S` induced from the topology on `Scheme` defined by `P`. +This agrees with the topology induced by `S.overPretopology P`, see +`AlgebraicGeometry.Scheme.overGrothendieckTopology_eq_toGrothendieck_overPretopology`. -/ +abbrev overGrothendieckTopology : GrothendieckTopology (Over S) := + (Scheme.grothendieckTopology P).over S + +lemma overGrothendieckTopology_eq_toGrothendieck_overPretopology : + S.overGrothendieckTopology P = (S.overPretopology P).toGrothendieck := by + ext X R + rw [GrothendieckTopology.mem_over_iff, Pretopology.mem_toGrothendieck] + constructor + · rintro ⟨T, ⟨𝒰, rfl⟩, hT⟩ + letI (i : 𝒰.J) : (𝒰.obj i).Over S := { hom := 𝒰.map i ≫ X.hom } + letI : 𝒰.Over S := + { over := inferInstance + isOver_map := fun i ↦ ⟨rfl⟩ } + use 𝒰.toPresieveOver, ⟨𝒰, inferInstance, rfl⟩ + rwa [Cover.toPresieveOver_le_arrows_iff] + · rintro ⟨T, ⟨𝒰, h, rfl⟩, hT⟩ + use Presieve.ofArrows 𝒰.obj 𝒰.map, ⟨𝒰, rfl⟩ + rwa [Cover.toPresieveOver_le_arrows_iff] at hT + +variable {S} + +lemma mem_overGrothendieckTopology (X : Over S) (R : Sieve X) : + R ∈ S.overGrothendieckTopology P X ↔ + ∃ (𝒰 : Cover.{u} P X.left) (_ : 𝒰.Over S), 𝒰.toPresieveOver ≤ R.arrows := by + rw [overGrothendieckTopology_eq_toGrothendieck_overPretopology] + constructor + · rintro ⟨T, ⟨𝒰, h, rfl⟩, hle⟩ + use 𝒰, h + · rintro ⟨𝒰, h𝒰, hle⟩ + exact ⟨𝒰.toPresieveOver, ⟨𝒰, h𝒰, rfl⟩, hle⟩ + +variable [Q.IsStableUnderComposition] + +variable (S) {P Q} in +lemma locallyCoverDense_of_le (hPQ : P ≤ Q) : + (MorphismProperty.Over.forget Q ⊤ S).LocallyCoverDense (overGrothendieckTopology P S) where + functorPushforward_functorPullback_mem X := by + intro ⟨T, hT⟩ + rw [mem_overGrothendieckTopology] at hT ⊢ + obtain ⟨𝒰, h, hle⟩ := hT + use 𝒰, h + rintro - - ⟨i⟩ + have p : Q (𝒰.obj i ↘ S) := by + rw [← comp_over (𝒰.map i) S] + exact Q.comp_mem _ _ (hPQ _ <| 𝒰.map_prop i) X.prop + use (𝒰.obj i).asOverProp S p, MorphismProperty.Over.homMk (𝒰.map i) (comp_over (𝒰.map i) S), 𝟙 _ + exact ⟨hle _ ⟨i⟩, rfl⟩ + +instance : (MorphismProperty.Over.forget P ⊤ S).LocallyCoverDense (overGrothendieckTopology P S) := + locallyCoverDense_of_le S le_rfl + +variable (S) {P Q} in +/-- If `P` and `Q` are morphism properties with `P ≤ Q`, this is the Grothendieck topology +induced via the forgetful functor `Q.Over ⊤ S ⥤ Over S` by the topology defined by `P`. -/ +abbrev smallGrothendieckTopologyOfLE (hPQ : P ≤ Q) : GrothendieckTopology (Q.Over ⊤ S) := + letI : (MorphismProperty.Over.forget Q ⊤ S).LocallyCoverDense (overGrothendieckTopology P S) := + locallyCoverDense_of_le S hPQ + (MorphismProperty.Over.forget Q ⊤ S).inducedTopology (S.overGrothendieckTopology P) + +/-- The Grothendieck topology on the category of schemes over `S` with `P` induced by `P`, i.e. +coverings are simply surjective families. This is the induced topology by the topology on `S` +defined by `P` via the inclusion `P.Over ⊤ S ⥤ Over S`. + +This is a special case of `smallGrothendieckTopologyOfLE` for the case `P = Q`. -/ +abbrev smallGrothendieckTopology : GrothendieckTopology (P.Over ⊤ S) := + (MorphismProperty.Over.forget P ⊤ S).inducedTopology (S.overGrothendieckTopology P) + +variable [Q.IsStableUnderBaseChange] [Q.HasOfPostcompProperty Q] + +/-- The pretopology defind on the subcategory of `S`-schemes satisfying `Q` where coverings +are given by `P`-coverings in `S`-schemes satisfying `Q`. +The most common case is `P = Q`. In this case, this is simply surjective families +in `S`-schemes with `P`. -/ +def smallPretopology : Pretopology (Q.Over ⊤ S) where + coverings Y R := ∃ (𝒰 : Cover.{u} P Y.left) (_ : 𝒰.Over S) (h : ∀ j : 𝒰.J, Q (𝒰.obj j ↘ S)), + R = 𝒰.toPresieveOverProp h + has_isos {X Y} f := ⟨coverOfIsIso f.left, inferInstance, fun _ ↦ Y.prop, + (Presieve.ofArrows_pUnit _).symm⟩ + pullbacks := by + rintro Y X f _ ⟨𝒰, h, p, rfl⟩ + refine ⟨𝒰.pullbackCoverOverProp' S f.left (Q := Q) Y.prop X.prop p, inferInstance, ?_, ?_⟩ + · intro j + apply MorphismProperty.Comma.prop + · exact (Presieve.ofArrows_pullback f (fun i ↦ ⟨(𝒰.obj i).asOver S, p i⟩) + (fun i ↦ ⟨(𝒰.map i).asOver S, trivial, trivial⟩)).symm + transitive := by + rintro X _ T ⟨𝒰, h, p, rfl⟩ H + choose V h pV hV using H + let 𝒱j (j : 𝒰.J) : (Cover P ((𝒰.obj j).asOverProp S (p j)).left) := + V ((𝒰.map j).asOverProp S) ⟨j⟩ + refine ⟨𝒰.bind (fun j ↦ 𝒱j j), inferInstance, fun j ↦ pV _ _ _, ?_⟩ + convert Presieve.ofArrows_bind _ (fun j ↦ ((𝒰.map j).asOverProp S)) _ + (fun Y f H j ↦ ((V f H).obj j).asOverProp S (pV _ _ _)) + (fun Y f H j ↦ ((V f H).map j).asOverProp S) + apply hV + +variable (S) {P Q} in +lemma smallGrothendieckTopologyOfLE_eq_toGrothendieck_smallPretopology (hPQ : P ≤ Q) : + S.smallGrothendieckTopologyOfLE hPQ = (S.smallPretopology P Q).toGrothendieck := by + ext X R + simp only [Pretopology.mem_toGrothendieck, Functor.mem_inducedTopology_sieves_iff, + MorphismProperty.Comma.forget_obj, mem_overGrothendieckTopology] + constructor + · intro ⟨𝒰, h, le⟩ + have hj (j : 𝒰.J) : Q (𝒰.obj j ↘ S) := by + rw [← comp_over (𝒰.map j)] + exact Q.comp_mem _ _ (hPQ _ <| 𝒰.map_prop _) X.prop + refine ⟨𝒰.toPresieveOverProp hj, ?_, ?_⟩ + · use 𝒰, h, hj + · rintro - - ⟨i⟩ + let fi : (𝒰.obj i).asOverProp S (hj i) ⟶ X := (𝒰.map i).asOverProp S + have : R.functorPushforward _ ((MorphismProperty.Over.forget Q ⊤ S).map fi) := le _ ⟨i⟩ + rwa [Sieve.functorPushforward_apply, + Sieve.mem_functorPushforward_iff_of_full_of_faithful] at this + · rintro ⟨T, ⟨𝒰, h, p, rfl⟩, le⟩ + use 𝒰, h + rintro - - ⟨i⟩ + exact ⟨(𝒰.obj i).asOverProp S (p i), (𝒰.map i).asOverProp S, 𝟙 _, le _ ⟨i⟩, rfl⟩ + +lemma smallGrothendieckTopology_eq_toGrothendieck_smallPretopology [P.HasOfPostcompProperty P] : + S.smallGrothendieckTopology P = (S.smallPretopology P P).toGrothendieck := + S.smallGrothendieckTopologyOfLE_eq_toGrothendieck_smallPretopology le_rfl + +variable {P Q} + +lemma mem_toGrothendieck_smallPretopology (X : Q.Over ⊤ S) (R : Sieve X) : + R ∈ (S.smallPretopology P Q).toGrothendieck _ X ↔ + ∀ x : X.left, ∃ (Y : Q.Over ⊤ S) (f : Y ⟶ X) (y : Y.left), + R f ∧ P f.left ∧ f.left.base y = x := by + rw [Pretopology.mem_toGrothendieck] + refine ⟨?_, fun h ↦ ?_⟩ + · rintro ⟨T, ⟨𝒰, h, p, rfl⟩, hle⟩ + intro x + obtain ⟨y, hy⟩ := 𝒰.covers x + refine ⟨(𝒰.obj (𝒰.f x)).asOverProp S (p _), (𝒰.map (𝒰.f x)).asOverProp S, y, hle _ ?_, + 𝒰.map_prop _, hy⟩ + use 𝒰.f x + · choose Y f y hf hP hy using h + let 𝒰 : X.left.Cover P := + { J := X.left, + obj := fun i ↦ (Y i).left + map := fun i ↦ (f i).left + map_prop := hP + f := id + covers := fun i ↦ ⟨y i, hy i⟩ } + letI : 𝒰.Over S := + { over := fun i ↦ inferInstance + isOver_map := fun i ↦ inferInstance } + refine ⟨𝒰.toPresieveOverProp fun i ↦ MorphismProperty.Comma.prop _, ?_, ?_⟩ + · use 𝒰, inferInstance, fun i ↦ MorphismProperty.Comma.prop _ + · rintro - - ⟨i⟩ + exact hf i + +lemma mem_smallGrothendieckTopology [P.HasOfPostcompProperty P] (X : P.Over ⊤ S) (R : Sieve X) : + R ∈ S.smallGrothendieckTopology P X ↔ + ∃ (𝒰 : Cover.{u} P X.left) (_ : 𝒰.Over S) (h : ∀ j, P (𝒰.obj j ↘ S)), + 𝒰.toPresieveOverProp h ≤ R.arrows := by + rw [smallGrothendieckTopology_eq_toGrothendieck_smallPretopology] + constructor + · rintro ⟨T, ⟨𝒰, h, p, rfl⟩, hle⟩ + use 𝒰, h, p + · rintro ⟨𝒰, h𝒰, p, hle⟩ + exact ⟨𝒰.toPresieveOverProp p, ⟨𝒰, h𝒰, p, rfl⟩, hle⟩ + +end AlgebraicGeometry.Scheme diff --git a/Mathlib/AlgebraicGeometry/Spec.lean b/Mathlib/AlgebraicGeometry/Spec.lean index b39f3a28bab75..b16f662644390 100644 --- a/Mathlib/AlgebraicGeometry/Spec.lean +++ b/Mathlib/AlgebraicGeometry/Spec.lean @@ -241,10 +241,10 @@ def Spec.locallyRingedSpaceMap {R S : CommRingCat.{u}} (f : R ⟶ S) : replace ha := (isUnit_map_iff (stalkIso S p).inv _).mp ha -- Porting note: `f` had to be made explicit replace ha := IsLocalHom.map_nonunit - (f := (Localization.localRingHom (PrimeSpectrum.comap f p).asIdeal p.asIdeal f _)) _ ha + (f := (Localization.localRingHom (PrimeSpectrum.comap f p).asIdeal p.asIdeal f _)) + ((stalkIso R ((PrimeSpectrum.comap f) p)).hom a) ha convert RingHom.isUnit_map (stalkIso R (PrimeSpectrum.comap f p)).inv ha - erw [← comp_apply, show stalkToFiberRingHom R _ = (stalkIso _ _).hom from rfl, - Iso.hom_inv_id, id_apply] + erw [← comp_apply, Iso.hom_inv_id, id_apply] @[simp] theorem Spec.locallyRingedSpaceMap_id (R : CommRingCat.{u}) : diff --git a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean index dbc4ac5a16007..10d725b7f0215 100644 --- a/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean +++ b/Mathlib/AlgebraicGeometry/ValuativeCriterion.lean @@ -242,9 +242,9 @@ lemma IsSeparated.of_valuativeCriterion [QuasiSeparated f] let S' : ValuativeCommSq f := ⟨S.R, S.K, S.i₁, S.i₂ ≫ pullback.fst f f ≫ f, hc⟩ have : Subsingleton S'.commSq.LiftStruct := hf S' let S'l₁ : S'.commSq.LiftStruct := ⟨S.i₂ ≫ pullback.fst f f, - by simp [← S.commSq.w_assoc], by simp⟩ + by simp [S', ← S.commSq.w_assoc], by simp [S']⟩ let S'l₂ : S'.commSq.LiftStruct := ⟨S.i₂ ≫ pullback.snd f f, - by simp [← S.commSq.w_assoc], by simp [pullback.condition]⟩ + by simp [S', ← S.commSq.w_assoc], by simp [S', pullback.condition]⟩ have h₁₂ : S'l₁ = S'l₂ := Subsingleton.elim _ _ constructor constructor diff --git a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean index 25c2c3588b0e9..7e25833d9f89f 100644 --- a/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean +++ b/Mathlib/AlgebraicTopology/AlternatingFaceMapComplex.lean @@ -80,14 +80,14 @@ theorem d_squared (n : ℕ) : objD X (n + 1) ≫ objD X n = 0 := by apply Finset.sum_bij φ · -- φ(S) is contained in Sᶜ intro ij hij - simp only [S, Finset.mem_univ, Finset.compl_filter, Finset.mem_filter, true_and, + simp only [S, φ, Finset.mem_univ, Finset.compl_filter, Finset.mem_filter, true_and, Fin.val_succ, Fin.coe_castLT] at hij ⊢ linarith · -- φ : S → Sᶜ is injective 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)⟩ + exact ⟨by simpa [φ] using congr_arg Prod.snd h, + by simpa [φ, Fin.castSucc_castLT] using congr_arg Fin.castSucc (congr_arg Prod.fst h)⟩ · -- φ : S → Sᶜ is surjective rintro ⟨i', j'⟩ hij' simp only [S, Finset.mem_univ, forall_true_left, Prod.forall, Finset.compl_filter, @@ -103,7 +103,7 @@ theorem d_squared (n : ℕ) : objD X (n + 1) ≫ objD X n = 0 := by 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] + · simp only [φ, Fin.val_succ, pow_add, pow_one, mul_neg, neg_neg, mul_one] apply mul_comm · rw [CategoryTheory.SimplicialObject.δ_comp_δ''] simpa [S] using hij diff --git a/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean b/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean index 7556fb09166e3..d1b827f3f5c7c 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/Decomposition.lean @@ -66,7 +66,7 @@ theorem decomposition_Q (n q : ℕ) : symm conv_rhs => rw [sub_eq_add_neg, add_comm] let q' : Fin (n + 1) := ⟨q, Nat.succ_le_iff.mp hqn⟩ - rw [← @Finset.add_sum_erase _ _ _ _ _ _ q' (by simp)] + rw [← @Finset.add_sum_erase _ _ _ _ _ _ q' (by simp [q'])] congr · have hnaq' : n = a + q := by omega simp only [Fin.val_mk, (HigherFacesVanish.of_P q n).comp_Hσ_eq hnaq', diff --git a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean index b6025650b82bb..3081d5036b92a 100644 --- a/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean +++ b/Mathlib/AlgebraicTopology/DoldKan/GammaCompN.lean @@ -6,6 +6,7 @@ Authors: Joël Riou import Mathlib.AlgebraicTopology.DoldKan.FunctorGamma import Mathlib.AlgebraicTopology.DoldKan.SplitSimplicialObject import Mathlib.CategoryTheory.Idempotents.HomologicalComplex +import Mathlib.Tactic.SuppressCompilation /-! The counit isomorphism of the Dold-Kan equivalence @@ -17,6 +18,7 @@ and `N₂Γ₂ : Γ₂ ⋙ N₂ ≅ 𝟭 (Karoubi (ChainComplex C ℕ))`. -/ +suppress_compilation noncomputable section diff --git a/Mathlib/AlgebraicTopology/SimplexCategory.lean b/Mathlib/AlgebraicTopology/SimplexCategory.lean index 115b2bc0a1851..156dc3423a3ca 100644 --- a/Mathlib/AlgebraicTopology/SimplexCategory.lean +++ b/Mathlib/AlgebraicTopology/SimplexCategory.lean @@ -231,6 +231,10 @@ def mkOfLe {n} (i j : Fin (n+1)) (h : i ≤ j) : ([1] : SimplexCategory) ⟶ [n] | 0, 1, _ => h } +@[simp] +lemma mkOfLe_refl {n} (j : Fin (n + 1)) : + mkOfLe j j (by omega) = [1].const [n] j := Hom.ext_one_left _ _ + /-- The morphism `[1] ⟶ [n]` that picks out the "diagonal composite" edge-/ def diag (n : ℕ) : ([1] : SimplexCategory) ⟶ [n] := mkOfLe 0 n (Fin.zero_le _) diff --git a/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean index c7ee1ad189a72..777aac3b212a6 100644 --- a/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplicialObject/Basic.lean @@ -484,10 +484,9 @@ instance : Category (CosimplicialObject C) := by namespace CosimplicialObject -set_option quotPrecheck false in /-- `X _[n]` denotes the `n`th-term of the cosimplicial object X -/ scoped[Simplicial] - notation:1000 X " _[" n "]" => + notation3:1000 X " _[" n "]" => (X : CategoryTheory.CosimplicialObject _).obj (SimplexCategory.mk n) instance {J : Type v} [SmallCategory J] [HasLimitsOfShape J C] : diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean index 6e545ab1fa48e..be2e7617b9773 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Basic.lean @@ -384,10 +384,10 @@ protected abbrev Truncated.cosk (n : ℕ) : SSet.Truncated n ⥤ SSet.{u} := SimplicialObject.Truncated.cosk n /-- The n-skeleton as an endofunctor on `SSet`. -/ -abbrev sk (n : ℕ) : SSet ⥤ SSet := SimplicialObject.sk n +abbrev sk (n : ℕ) : SSet.{u} ⥤ SSet.{u} := SimplicialObject.sk n /-- The n-coskeleton as an endofunctor on `SSet`. -/ -abbrev cosk (n : ℕ) : SSet ⥤ SSet := SimplicialObject.cosk n +abbrev cosk (n : ℕ) : SSet.{u} ⥤ SSet.{u} := SimplicialObject.cosk n end diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Coskeletal.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Coskeletal.lean new file mode 100644 index 0000000000000..93eed2ed3a913 --- /dev/null +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Coskeletal.lean @@ -0,0 +1,256 @@ +/- +Copyright (c) 2024 Emily Riehl. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Emily Riehl, Joël Riou +-/ +import Mathlib.AlgebraicTopology.SimplicialObject.Coskeletal +import Mathlib.AlgebraicTopology.SimplicialSet.StrictSegal +import Mathlib.CategoryTheory.Functor.KanExtension.Adjunction +import Mathlib.CategoryTheory.Functor.KanExtension.Basic + +/-! +# Coskeletal simplicial sets + +In this file, we prove that if `X` is `StrictSegal` then `X` is 2-coskeletal, +i.e. `X ≅ (cosk 2).obj X`. In particular, nerves of categories are 2-coskeletal. + +This isomorphism follows from the fact that `rightExtensionInclusion X 2` is a right Kan +extension. In fact, we show that when `X` is `StrictSegal` then +`(rightExtensionInclusion X n).IsPointwiseRightKanExtension` holds. + +As an example, `SimplicialObject.IsCoskeletal (nerve C) 2` shows that that nerves of categories +are 2-coskeletal. +-/ + + +universe v u + +open CategoryTheory Simplicial SimplexCategory Opposite Category Functor Limits + +namespace SSet + +namespace Truncated + +/-- The identity natural transformation exhibits a simplicial set as a right extension of its +restriction along `(Truncated.inclusion (n := n)).op`.-/ +@[simps!] +def rightExtensionInclusion (X : SSet.{u}) (n : ℕ) : + RightExtension (Truncated.inclusion (n := n)).op + ((Truncated.inclusion n).op ⋙ X) := RightExtension.mk _ (𝟙 _) + +end Truncated + +section + +local notation (priority := high) "[" n "]" => SimplexCategory.mk n + +local macro:max (priority := high) "[" n:term "]₂" : term => + `((⟨SimplexCategory.mk $n, by dsimp; omega⟩ : SimplexCategory.Truncated 2)) + +open StructuredArrow + +namespace StrictSegal +variable (X : SSet.{u}) [StrictSegal X] + +namespace isPointwiseRightKanExtensionAt + +/-- A morphism in `SimplexCategory` with domain `[0]`, `[1]`, or `[2]` defines an object in the +comma category `StructuredArrow (op [n]) (Truncated.inclusion (n := 2)).op`.-/ +abbrev strArrowMk₂ {i : ℕ} {n : ℕ} (φ : [i] ⟶ [n]) (hi : i ≤ 2) : + StructuredArrow (op [n]) (Truncated.inclusion (n := 2)).op := + StructuredArrow.mk (Y := op ⟨[i], hi⟩) (by exact φ.op) + +/-- Given a term in the cone over the diagram +`(proj (op [n]) ((Truncated.inclusion 2).op ⋙ (Truncated.inclusion 2).op ⋙ X)` where `X` is +Strict Segal, one can produce an `n`-simplex in `X`. -/ +@[simp] +noncomputable def lift {X : SSet.{u}} [StrictSegal X] {n} + (s : Cone (proj (op [n]) (Truncated.inclusion 2).op ⋙ + (Truncated.inclusion 2).op ⋙ X)) (x : s.pt) : X _[n] := + StrictSegal.spineToSimplex { + vertex := fun i ↦ s.π.app (.mk (Y := op [0]₂) (.op (SimplexCategory.const _ _ i))) x + arrow := fun i ↦ s.π.app (.mk (Y := op [1]₂) (.op (mkOfLe _ _ (Fin.castSucc_le_succ i)))) x + arrow_src := fun i ↦ by + let φ : strArrowMk₂ (mkOfLe _ _ (Fin.castSucc_le_succ i)) (by simp) ⟶ + strArrowMk₂ ([0].const _ i.castSucc) (by simp) := + StructuredArrow.homMk (δ 1).op + (Quiver.Hom.unop_inj (by ext x; fin_cases x; rfl)) + exact congr_fun (s.w φ) x + arrow_tgt := fun i ↦ by + dsimp + let φ : strArrowMk₂ (mkOfLe _ _ (Fin.castSucc_le_succ i)) (by simp) ⟶ + strArrowMk₂ ([0].const _ i.succ) (by simp) := + StructuredArrow.homMk (δ 0).op + (Quiver.Hom.unop_inj (by ext x; fin_cases x; rfl)) + exact congr_fun (s.w φ) x } + +lemma fac_aux₁ {n : ℕ} + (s : Cone (proj (op [n]) (Truncated.inclusion 2).op ⋙ (Truncated.inclusion 2).op ⋙ X)) + (x : s.pt) (i : ℕ) (hi : i < n) : + X.map (mkOfSucc ⟨i, hi⟩).op (lift s x) = + s.π.app (strArrowMk₂ (mkOfSucc ⟨i, hi⟩) (by omega)) x := by + dsimp [lift] + rw [spineToSimplex_arrow] + rfl + +lemma fac_aux₂ {n : ℕ} + (s : Cone (proj (op [n]) (Truncated.inclusion 2).op ⋙ (Truncated.inclusion 2).op ⋙ X)) + (x : s.pt) (i j : ℕ) (hij : i ≤ j) (hj : j ≤ n) : + X.map (mkOfLe ⟨i, by omega⟩ ⟨j, by omega⟩ hij).op (lift s x) = + s.π.app (strArrowMk₂ (mkOfLe ⟨i, by omega⟩ ⟨j, by omega⟩ hij) (by omega)) x := by + obtain ⟨k, hk⟩ := Nat.le.dest hij + revert i j + induction k with + | zero => + rintro i j hij hj hik + obtain rfl : i = j := by omega + have : mkOfLe ⟨i, Nat.lt_add_one_of_le hj⟩ ⟨i, Nat.lt_add_one_of_le hj⟩ (by omega) = + [1].const [0] 0 ≫ [0].const [n] ⟨i, Nat.lt_add_one_of_le hj⟩ := Hom.ext_one_left _ _ + rw [this] + let α : (strArrowMk₂ ([0].const [n] ⟨i, Nat.lt_add_one_of_le hj⟩) (by omega)) ⟶ + (strArrowMk₂ ([1].const [0] 0 ≫ [0].const [n] ⟨i, Nat.lt_add_one_of_le hj⟩) (by omega)) := + StructuredArrow.homMk (([1].const [0] 0).op) (by simp; rfl) + have nat := congr_fun (s.π.naturality α) x + dsimp only [Fin.val_zero, Nat.add_zero, id_eq, Int.reduceNeg, Int.Nat.cast_ofNat_Int, + Int.reduceAdd, Fin.eta, comp_obj, StructuredArrow.proj_obj, op_obj, const_obj_obj, + const_obj_map, types_comp_apply, types_id_apply, Functor.comp_map, StructuredArrow.proj_map, + op_map] at nat + rw [nat, op_comp, Functor.map_comp] + simp only [types_comp_apply] + refine congrArg (X.map ([1].const [0] 0).op) ?_ + unfold strArrowMk₂ + rw [lift, StrictSegal.spineToSimplex_vertex] + congr + | succ k hk => + intro i j hij hj hik + let α := strArrowMk₂ (mkOfLeComp (n := n) ⟨i, by omega⟩ ⟨i + k, by omega⟩ + ⟨j, by omega⟩ (by simp) + (by simp only [Fin.mk_le_mk]; omega)) (by rfl) + let α₀ := strArrowMk₂ (mkOfLe (n := n) ⟨i + k, by omega⟩ ⟨j, by omega⟩ + (by simp only [Fin.mk_le_mk]; omega)) (by simp) + let α₁ := strArrowMk₂ (mkOfLe (n := n) ⟨i, by omega⟩ ⟨j, by omega⟩ + (by simp only [Fin.mk_le_mk]; omega)) (by simp) + let α₂ := strArrowMk₂ (mkOfLe (n := n) ⟨i, by omega⟩ ⟨i + k, by omega⟩ (by simp)) (by simp) + let β₀ : α ⟶ α₀ := StructuredArrow.homMk ((mkOfSucc 1).op) (Quiver.Hom.unop_inj + (by ext x; fin_cases x <;> rfl)) + let β₁ : α ⟶ α₁ := StructuredArrow.homMk ((δ 1).op) (Quiver.Hom.unop_inj + (by ext x; fin_cases x <;> rfl)) + let β₂ : α ⟶ α₂ := StructuredArrow.homMk ((mkOfSucc 0).op) (Quiver.Hom.unop_inj + (by ext x; fin_cases x <;> rfl)) + have h₀ : X.map α₀.hom (lift s x) = s.π.app α₀ x := by + obtain rfl : j = (i + k) + 1 := by omega + exact fac_aux₁ _ _ _ _ (by omega) + have h₂ : X.map α₂.hom (lift s x) = s.π.app α₂ x := + hk i (i + k) (by simp) (by omega) rfl + change X.map α₁.hom (lift s x) = s.π.app α₁ x + have : X.map α.hom (lift s x) = s.π.app α x := by + apply StrictSegal.spineInjective + apply Path.ext' + intro t + dsimp only [spineEquiv] + rw [Equiv.coe_fn_mk, spine_arrow, spine_arrow, + ← FunctorToTypes.map_comp_apply] + match t with + | 0 => + have : α.hom ≫ (mkOfSucc 0).op = α₂.hom := + Quiver.Hom.unop_inj (by ext x ; fin_cases x <;> rfl) + rw [this, h₂, ← congr_fun (s.w β₂) x] + rfl + | 1 => + have : α.hom ≫ (mkOfSucc 1).op = α₀.hom := + Quiver.Hom.unop_inj (by ext x ; fin_cases x <;> rfl) + rw [this, h₀, ← congr_fun (s.w β₀) x] + rfl + rw [← StructuredArrow.w β₁, FunctorToTypes.map_comp_apply, this, ← s.w β₁] + dsimp + +lemma fac_aux₃ {n : ℕ} + (s : Cone (proj (op [n]) (Truncated.inclusion 2).op ⋙ (Truncated.inclusion 2).op ⋙ X)) + (x : s.pt) (φ : [1] ⟶ [n]) : + X.map φ.op (lift s x) = s.π.app (strArrowMk₂ φ (by omega)) x := by + obtain ⟨i, j, hij, rfl⟩ : ∃ i j hij, φ = mkOfLe i j hij := + ⟨φ.toOrderHom 0, φ.toOrderHom 1, φ.toOrderHom.monotone (by simp), + Hom.ext_one_left _ _ rfl rfl⟩ + exact fac_aux₂ _ _ _ _ _ _ (by omega) + +end isPointwiseRightKanExtensionAt + +open Truncated + +open isPointwiseRightKanExtensionAt in +/-- A strict Segal simplicial set is 2-coskeletal. -/ +noncomputable def isPointwiseRightKanExtensionAt (n : ℕ) : + (rightExtensionInclusion X 2).IsPointwiseRightKanExtensionAt ⟨[n]⟩ where + lift s x := lift (X := X) s x + fac s j := by + ext x + obtain ⟨⟨i, hi⟩, ⟨f : _ ⟶ _⟩, rfl⟩ := j.mk_surjective + obtain ⟨i, rfl⟩ : ∃ j, SimplexCategory.mk j = i := ⟨_, i.mk_len⟩ + dsimp at hi ⊢ + apply StrictSegal.spineInjective + dsimp + ext k + · dsimp only [spineEquiv, Equiv.coe_fn_mk] + erw [spine_map_vertex] + rw [spine_spineToSimplex, spine_vertex] + let α : strArrowMk₂ f hi ⟶ strArrowMk₂ ([0].const [n] (f.toOrderHom k)) (by omega) := + StructuredArrow.homMk (([0].const _ (by exact k)).op) (by simp; rfl) + exact congr_fun (s.w α).symm x + · dsimp only [spineEquiv, Equiv.coe_fn_mk, spine_arrow] + rw [← FunctorToTypes.map_comp_apply] + let α : strArrowMk₂ f hi ⟶ strArrowMk₂ (mkOfSucc k ≫ f) (by omega) := + StructuredArrow.homMk (mkOfSucc k).op (by simp; rfl) + exact (isPointwiseRightKanExtensionAt.fac_aux₃ _ _ _ _).trans (congr_fun (s.w α).symm x) + uniq s m hm := by + ext x + apply StrictSegal.spineInjective (X := X) + dsimp [spineEquiv] + rw [StrictSegal.spine_spineToSimplex] + ext i + · exact congr_fun (hm (StructuredArrow.mk (Y := op [0]₂) ([0].const [n] i).op)) x + · exact congr_fun (hm (.mk (Y := op [1]₂) (.op (mkOfLe _ _ (Fin.castSucc_le_succ i))))) x + +/-- Since `StrictSegal.isPointwiseRightKanExtensionAt` proves that the appropriate +cones are limit cones, `rightExtensionInclusion X 2` is a pointwise right Kan extension.-/ +noncomputable def isPointwiseRightKanExtension : + (rightExtensionInclusion X 2).IsPointwiseRightKanExtension := + fun Δ => isPointwiseRightKanExtensionAt X Δ.unop.len + +theorem isRightKanExtension : + X.IsRightKanExtension (𝟙 ((inclusion 2).op ⋙ X)) := + RightExtension.IsPointwiseRightKanExtension.isRightKanExtension + (isPointwiseRightKanExtension X) + +/-- When `X` is `StrictSegal`, `X` is 2-coskeletal. -/ +instance isCoskeletal : SimplicialObject.IsCoskeletal X 2 where + isRightKanExtension := isRightKanExtension X + +end StrictSegal + +end + +end SSet + +namespace CategoryTheory + +namespace Nerve + +open SSet + +example (C : Type u) [Category.{v} C] : + SimplicialObject.IsCoskeletal (nerve C) 2 := by infer_instance + +/-- The essential data of the nerve functor is contained in the 2-truncation, which is +recorded by the composite functor `nerveFunctor₂`.-/ +def nerveFunctor₂ : Cat.{v, u} ⥤ SSet.Truncated 2 := nerveFunctor ⋙ truncation 2 + +/-- The natural isomorphism between `nerveFunctor` and `nerveFunctor₂ ⋙ Truncated.cosk 2` whose +components `nerve C ≅ (Truncated.cosk 2).obj (nerveFunctor₂.obj C)` shows that nerves of categories +are 2-coskeletal.-/ +noncomputable def cosk₂Iso : nerveFunctor.{v, u} ≅ nerveFunctor₂.{v, u} ⋙ Truncated.cosk 2 := + NatIso.ofComponents (fun C ↦ (nerve C).isoCoskOfIsCoskeletal 2) + (fun _ ↦ (coskAdj 2).unit.naturality _) + +end Nerve + +end CategoryTheory diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean index c82254637aaf3..a24814b5a2a14 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Nerve.lean @@ -37,7 +37,7 @@ instance {C : Type*} [Category C] {Δ : SimplexCategoryᵒᵖ} : Category ((nerv /-- The nerve of a category, as a functor `Cat ⥤ SSet` -/ @[simps] -def nerveFunctor : Cat ⥤ SSet where +def nerveFunctor : Cat.{v, u} ⥤ SSet where obj C := nerve C map F := { app := fun _ => (F.mapComposableArrows _).obj } diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean b/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean index 33e4d07da1bce..ff920be3bfa29 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/Path.lean @@ -64,6 +64,13 @@ def spine (n : ℕ) (Δ : X _[n]) : X.Path n where simp only [← FunctorToTypes.map_comp_apply, ← op_comp] rw [SimplexCategory.δ_zero_mkOfSucc] +lemma spine_map_vertex {n : ℕ} (x : X _[n]) {m : ℕ} (φ : ([m] : SimplexCategory) ⟶ [n]) + (i : Fin (m + 1)) : + (spine X m (X.map φ.op x)).vertex i = (spine X n x).vertex (φ.toOrderHom i) := by + dsimp [spine] + rw [← FunctorToTypes.map_comp_apply] + rfl + lemma spine_map_subinterval {n : ℕ} (j l : ℕ) (hjl : j + l ≤ n) (Δ : X _[n]) : X.spine l (X.map (subinterval j l (by omega)).op Δ) = (X.spine n Δ).interval j l (by omega) := by diff --git a/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean b/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean index 7436832a79255..d45282b986c0d 100644 --- a/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean +++ b/Mathlib/AlgebraicTopology/SimplicialSet/StrictSegal.lean @@ -19,6 +19,10 @@ Examples of `StrictSegal` simplicial sets are given by nerves of categories. TODO: Show that these are the only examples: that a `StrictSegal` simplicial set is isomorphic to the nerve of its homotopy category. + +`StrictSegal` simplicial sets have an important property of being 2-coskeletal which is proven +in `Mathlib.AlgebraicTopology.SimplicialSet.Coskeletal`. + -/ universe v u diff --git a/Mathlib/Analysis/Analytic/Basic.lean b/Mathlib/Analysis/Analytic/Basic.lean index 3ebd74ae9c5f3..e1e5359b0a1de 100644 --- a/Mathlib/Analysis/Analytic/Basic.lean +++ b/Mathlib/Analysis/Analytic/Basic.lean @@ -530,6 +530,15 @@ theorem HasFPowerSeriesAt.congr (hf : HasFPowerSeriesAt f p x) (hg : f =ᶠ[𝓝 (h₁.mono (lt_min h₁.r_pos h₂pos) inf_le_left).congr fun y hy => h₂ (EMetric.ball_subset_ball inf_le_right hy)⟩ +theorem HasFPowerSeriesWithinOnBall.unique (hf : HasFPowerSeriesWithinOnBall f p s x r) + (hg : HasFPowerSeriesWithinOnBall g p s x r) : + (insert x s ∩ EMetric.ball x r).EqOn f g := fun _ hy ↦ + (hf.hasSum_sub hy).unique (hg.hasSum_sub hy) + +theorem HasFPowerSeriesOnBall.unique (hf : HasFPowerSeriesOnBall f p x r) + (hg : HasFPowerSeriesOnBall g p x r) : (EMetric.ball x r).EqOn f g := fun _ hy ↦ + (hf.hasSum_sub hy).unique (hg.hasSum_sub hy) + protected theorem HasFPowerSeriesWithinAt.eventually (hf : HasFPowerSeriesWithinAt f p s x) : ∀ᶠ r : ℝ≥0∞ in 𝓝[>] 0, HasFPowerSeriesWithinOnBall f p s x r := let ⟨_, hr⟩ := hf diff --git a/Mathlib/Analysis/Analytic/ChangeOrigin.lean b/Mathlib/Analysis/Analytic/ChangeOrigin.lean index 45dce2a33326c..176f6f15e6afc 100644 --- a/Mathlib/Analysis/Analytic/ChangeOrigin.lean +++ b/Mathlib/Analysis/Analytic/ChangeOrigin.lean @@ -232,6 +232,14 @@ theorem radius_le_radius_derivSeries : p.radius ≤ p.derivSeries.radius := by apply mul_le_of_le_one_left (norm_nonneg _) exact ContinuousLinearMap.opNorm_le_bound _ zero_le_one (by simp) +theorem derivSeries_eq_zero {n : ℕ} (hp : p (n + 1) = 0) : p.derivSeries n = 0 := by + suffices p.changeOriginSeries 1 n = 0 by ext v; simp [derivSeries, this] + apply Finset.sum_eq_zero (fun s hs ↦ ?_) + ext v + have : p (1 + n) = 0 := p.congr_zero (by abel) hp + simp [changeOriginSeriesTerm, ContinuousMultilinearMap.curryFinFinset_apply, + ContinuousMultilinearMap.zero_apply, this] + end -- From this point on, assume that the space is complete, to make sure that series that converge diff --git a/Mathlib/Analysis/Analytic/Composition.lean b/Mathlib/Analysis/Analytic/Composition.lean index 472d06dd79024..29001e428114c 100644 --- a/Mathlib/Analysis/Analytic/Composition.lean +++ b/Mathlib/Analysis/Analytic/Composition.lean @@ -1051,16 +1051,15 @@ theorem length_sigmaCompositionAux (a : Composition n) (b : Composition a.length show List.length ((splitWrtComposition a.blocks b)[i.1]) = blocksFun b i by rw [getElem_map_rev List.length, getElem_of_eq (map_length_splitWrtComposition _ _)]; rfl -set_option linter.deprecated false in theorem blocksFun_sigmaCompositionAux (a : Composition n) (b : Composition a.length) (i : Fin b.length) (j : Fin (blocksFun b i)) : blocksFun (sigmaCompositionAux a b ⟨i, (length_gather a b).symm ▸ i.2⟩) ⟨j, (length_sigmaCompositionAux a b i).symm ▸ j.2⟩ = - blocksFun a (embedding b i j) := - show get (get _ ⟨_, _⟩) ⟨_, _⟩ = a.blocks.get ⟨_, _⟩ by - rw [get_of_eq (get_splitWrtComposition _ _ _), get_drop', get_take']; rfl + blocksFun a (embedding b i j) := by + unfold sigmaCompositionAux + rw [blocksFun, get_eq_getElem, getElem_of_eq (getElem_splitWrtComposition _ _ _ _), + getElem_drop, getElem_take]; rfl -set_option linter.deprecated false in /-- Auxiliary lemma to prove that the composition of formal multilinear series is associative. Consider a composition `a` of `n` and a composition `b` of `a.length`. Grouping together some diff --git a/Mathlib/Analysis/Analytic/Inverse.lean b/Mathlib/Analysis/Analytic/Inverse.lean index 6efcaa447e727..6ef7fff93cce3 100644 --- a/Mathlib/Analysis/Analytic/Inverse.lean +++ b/Mathlib/Analysis/Analytic/Inverse.lean @@ -435,7 +435,7 @@ theorem radius_rightInv_pos_of_radius_pos_aux2 {x : E} {n : ℕ} (hn : 2 ≤ n + calc ∑ k ∈ Ico 1 (n + 1), a ^ k * ‖p.rightInv i x k‖ = a * I + ∑ k ∈ Ico 2 (n + 1), a ^ k * ‖p.rightInv i x k‖ := by - simp only [LinearIsometryEquiv.norm_map, pow_one, rightInv_coeff_one, + simp only [I, LinearIsometryEquiv.norm_map, pow_one, rightInv_coeff_one, show Ico (1 : ℕ) 2 = {1} from Nat.Ico_succ_singleton 1, sum_singleton, ← sum_Ico_consecutive _ one_le_two hn] _ = @@ -465,8 +465,8 @@ theorem radius_rightInv_pos_of_radius_pos_aux2 {x : E} {n : ℕ} (hn : 2 ≤ n + _ = I * a + I * C * ∑ k ∈ Ico 2 (n + 1), a ^ k * ∑ c ∈ ({c | 1 < Composition.length c}.toFinset : Finset (Composition k)), r ^ c.length * ∏ j, ‖p.rightInv i x (c.blocksFun j)‖ := by - simp_rw [mul_assoc C, ← mul_sum, ← mul_assoc, mul_comm _ ‖(i.symm : F →L[𝕜] E)‖, mul_assoc, - ← mul_sum, ← mul_assoc, mul_comm _ C, mul_assoc, ← mul_sum] + simp_rw [I, mul_assoc C, ← mul_sum, ← mul_assoc, mul_comm _ ‖(i.symm : F →L[𝕜] E)‖, + mul_assoc, ← mul_sum, ← mul_assoc, mul_comm _ C, mul_assoc, ← mul_sum] ring _ ≤ I * a + I * C * ∑ k ∈ Ico 2 (n + 1), (r * ∑ j ∈ Ico 1 n, a ^ j * ‖p.rightInv i x j‖) ^ k := by diff --git a/Mathlib/Analysis/Analytic/IteratedFDeriv.lean b/Mathlib/Analysis/Analytic/IteratedFDeriv.lean new file mode 100644 index 0000000000000..b4c95ff5110a4 --- /dev/null +++ b/Mathlib/Analysis/Analytic/IteratedFDeriv.lean @@ -0,0 +1,277 @@ +/- +Copyright (c) 2024 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastien Gouëzel +-/ +import Mathlib.Analysis.Calculus.ContDiff.Basic +import Mathlib.Analysis.Calculus.ContDiff.CPolynomial +import Mathlib.Data.Fintype.Perm + +/-! +# The iterated derivative of an analytic function + +If a function is analytic, written as `f (x + y) = ∑ pₙ (y, ..., y)` then its `n`-th iterated +derivative at `x` is given by `(v₁, ..., vₙ) ↦ ∑ pₙ (v_{σ (1)}, ..., v_{σ (n)})` where the sum +is over all permutations of `{1, ..., n}`. In particular, it is symmetric. + +This generalizes the result of `HasFPowerSeriesOnBall.factorial_smul` giving +`D^n f (v, ..., v) = n! * pₙ (v, ..., v)`. + +## Main result + +* `HasFPowerSeriesOnBall.iteratedFDeriv_eq_sum` shows that + `iteratedFDeriv 𝕜 n f x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i))`, + when `f` has `p` as power series within the set `s` on the ball `B (x, r)`. +* `ContDiffAt.iteratedFDeriv_comp_perm` proves the symmetry of the iterated derivative of an + analytic function, in the form `iteratedFDeriv 𝕜 n f x (v ∘ σ) = iteratedFDeriv 𝕜 n f x v` + for any permutation `σ` of `Fin n`. + +Versions within sets are also given. + +## Implementation + +To prove the formula for the iterated derivative, we decompose an analytic function as +the sum of `fun y ↦ pₙ (y, ..., y)` and the rest. For the former, its iterated derivative follows +from the formula for iterated derivatives of multilinear maps +(see `ContinuousMultilinearMap.iteratedFDeriv_comp_diagonal`). For the latter, we show by +induction on `n` that if the `n`-th term in a power series is zero, then the `n`-th iterated +derivative vanishes (see `HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_zero`). + +All these results are proved assuming additionally that the function is analytic on the relevant +set (which does not follow from the fact that the function has a power series, if the target space +is not complete). This makes it possible to avoid all completeness assumptions in the final +statements. When needed, we give versions of some statements assuming completeness and dropping +analyticity, for ease of use. +-/ + +open scoped ENNReal Topology ContDiff +open Equiv Set + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] + {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] + {f : E → F} {p : FormalMultilinearSeries 𝕜 E F} {s : Set E} {x : E} {r : ℝ≥0∞} + +/-- Formal multilinear series associated to the iterated derivative, defined by iterating +`p ↦ p.derivSeries` and currying suitably. It is defined so that, if a function has `p` as a power +series, then its iterated derivative of order `k` has `p.iteratedFDerivSeries k` as a power +series. -/ +noncomputable def FormalMultilinearSeries.iteratedFDerivSeries + (p : FormalMultilinearSeries 𝕜 E F) (k : ℕ) : + FormalMultilinearSeries 𝕜 E (E [×k]→L[𝕜] F) := + match k with + | 0 => (continuousMultilinearCurryFin0 𝕜 E F).symm + |>.toContinuousLinearEquiv.toContinuousLinearMap.compFormalMultilinearSeries p + | (k + 1) => (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (k + 1) ↦ E) F).symm + |>.toContinuousLinearEquiv.toContinuousLinearMap.compFormalMultilinearSeries + (p.iteratedFDerivSeries k).derivSeries + +/-- If a function has a power series on a ball, then so do its iterated derivatives. -/ +protected theorem HasFPowerSeriesWithinOnBall.iteratedFDerivWithin + (h : HasFPowerSeriesWithinOnBall f p s x r) (h' : AnalyticOn 𝕜 f s) + (k : ℕ) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) : + HasFPowerSeriesWithinOnBall (iteratedFDerivWithin 𝕜 k f s) + (p.iteratedFDerivSeries k) s x r := by + induction k with + | zero => + exact (continuousMultilinearCurryFin0 𝕜 E F).symm + |>.toContinuousLinearEquiv.toContinuousLinearMap.comp_hasFPowerSeriesWithinOnBall h + | succ k ih => + rw [iteratedFDerivWithin_succ_eq_comp_left] + apply (continuousMultilinearCurryLeftEquiv 𝕜 (fun _ : Fin (k + 1) ↦ E) F).symm + |>.toContinuousLinearEquiv.toContinuousLinearMap.comp_hasFPowerSeriesWithinOnBall + (ih.fderivWithin_of_mem_of_analyticOn (h'.iteratedFDerivWithin hs _) hs hx) + +lemma FormalMultilinearSeries.iteratedFDerivSeries_eq_zero {k n : ℕ} + (h : p (n + k) = 0) : p.iteratedFDerivSeries k n = 0 := by + induction k generalizing n with + | zero => + ext + have : p n = 0 := p.congr_zero rfl h + simp [FormalMultilinearSeries.iteratedFDerivSeries, this] + | succ k ih => + ext + simp only [iteratedFDerivSeries, Nat.succ_eq_add_one, + ContinuousLinearMap.compFormalMultilinearSeries_apply, + ContinuousLinearMap.compContinuousMultilinearMap_coe, ContinuousLinearEquiv.coe_coe, + LinearIsometryEquiv.coe_toContinuousLinearEquiv, Function.comp_apply, + continuousMultilinearCurryLeftEquiv_symm_apply, ContinuousMultilinearMap.zero_apply] + rw [derivSeries_eq_zero] + · rfl + · apply ih + apply p.congr_zero (by abel) h + +/-- If the `n`-th term in a power series is zero, then the `n`-th derivative of the corresponding +function vanishes. -/ +lemma HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_zero + (h : HasFPowerSeriesWithinOnBall f p s x r) (h' : AnalyticOn 𝕜 f s) + (hu : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (hn : p n = 0) : + iteratedFDerivWithin 𝕜 n f s x = 0 := by + have : iteratedFDerivWithin 𝕜 n f s x = p.iteratedFDerivSeries n 0 (fun _ ↦ 0) := + ((h.iteratedFDerivWithin h' n hu hx).coeff_zero _).symm + rw [this, p.iteratedFDerivSeries_eq_zero (p.congr_zero (Nat.zero_add n).symm hn)] + rfl + +lemma ContinuousMultilinearMap.iteratedFDeriv_comp_diagonal + {n : ℕ} (f : E [×n]→L[𝕜] F) (x : E) (v : Fin n → E) : + iteratedFDeriv 𝕜 n (fun x ↦ f (fun _ ↦ x)) x v = ∑ σ : Perm (Fin n), f (fun i ↦ v (σ i)) := by + rw [← sum_comp (Equiv.inv (Perm (Fin n)))] + let g : E →L[𝕜] (Fin n → E) := ContinuousLinearMap.pi (fun i ↦ ContinuousLinearMap.id 𝕜 E) + change iteratedFDeriv 𝕜 n (f ∘ g) x v = _ + rw [ContinuousLinearMap.iteratedFDeriv_comp_right _ f.contDiff _ le_rfl, f.iteratedFDeriv_eq] + simp only [ContinuousMultilinearMap.iteratedFDeriv, + ContinuousMultilinearMap.compContinuousLinearMap_apply, ContinuousMultilinearMap.sum_apply, + ContinuousMultilinearMap.iteratedFDerivComponent_apply, Set.mem_range, Pi.compRightL_apply] + rw [← sum_comp (Equiv.embeddingEquivOfFinite (Fin n))] + congr with σ + congr with i + have A : ∃ y, σ y = i := by + have : Function.Bijective σ := (Fintype.bijective_iff_injective_and_card _).2 ⟨σ.injective, rfl⟩ + exact this.surjective i + rcases A with ⟨y, rfl⟩ + simp only [EmbeddingLike.apply_eq_iff_eq, exists_eq, ↓reduceDIte, + Function.Embedding.toEquivRange_symm_apply_self, ContinuousLinearMap.coe_pi', + ContinuousLinearMap.coe_id', id_eq, g] + congr 1 + symm + simp [coe_fn_mk, inv_apply, Perm.inv_def, + ofBijective_symm_apply_apply, Function.Embedding.equivOfFiniteSelfEmbedding] + +private lemma HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_sum_of_subset + (h : HasFPowerSeriesWithinOnBall f p s x r) (h' : AnalyticOn 𝕜 f s) + (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) + {n : ℕ} (v : Fin n → E) (h's : s ⊆ EMetric.ball x r) : + iteratedFDerivWithin 𝕜 n f s x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i)) := by + have I : insert x s ∩ EMetric.ball x r = s := by + rw [Set.insert_eq_of_mem hx] + exact Set.inter_eq_left.2 h's + have fcont : ContDiffOn 𝕜 (↑n) f s := by + apply AnalyticOn.contDiffOn _ hs + simpa [I] using h' + let g : E → F := fun z ↦ p n (fun _ ↦ z - x) + have gcont : ContDiff 𝕜 ω g := by + apply (p n).contDiff.comp + exact contDiff_pi.2 (fun i ↦ contDiff_id.sub contDiff_const) + let q : FormalMultilinearSeries 𝕜 E F := fun k ↦ if h : n = k then (h ▸ p n) else 0 + have A : HasFiniteFPowerSeriesOnBall g q x (n + 1) r := by + apply HasFiniteFPowerSeriesOnBall.mk' _ h.r_pos + · intro y hy + rw [Finset.sum_eq_single_of_mem n] + · simp [q, g] + · simp + · intro i hi h'i + simp [q, h'i.symm] + · intro m hm + have : n ≠ m := by omega + simp [q, this] + have B : HasFPowerSeriesWithinOnBall g q s x r := + A.toHasFPowerSeriesOnBall.hasFPowerSeriesWithinOnBall + have J1 : iteratedFDerivWithin 𝕜 n f s x = + iteratedFDerivWithin 𝕜 n g s x + iteratedFDerivWithin 𝕜 n (f - g) s x := by + have : f = g + (f - g) := by abel + nth_rewrite 1 [this] + rw [iteratedFDerivWithin_add_apply (gcont.of_le le_top).contDiffOn + (by exact fcont.sub (gcont.of_le le_top).contDiffOn) hs hx] + have J2 : iteratedFDerivWithin 𝕜 n (f - g) s x = 0 := by + apply (h.sub B).iteratedFDerivWithin_eq_zero (h'.sub ?_) hs hx + · simp [q] + · apply gcont.contDiffOn.analyticOn + have J3 : iteratedFDerivWithin 𝕜 n g s x = iteratedFDeriv 𝕜 n g x := + iteratedFDerivWithin_eq_iteratedFDeriv hs (gcont.of_le le_top).contDiffAt hx + simp only [J1, J3, J2, add_zero] + let g' : E → F := fun z ↦ p n (fun _ ↦ z) + have : g = fun z ↦ g' (z - x) := rfl + rw [this, iteratedFDeriv_comp_sub] + exact (p n).iteratedFDeriv_comp_diagonal _ v + +/-- If a function has a power series in a ball, then its `n`-th iterated derivative is given by +`(v₁, ..., vₙ) ↦ ∑ pₙ (v_{σ (1)}, ..., v_{σ (n)})` where the sum is over all +permutations of `{1, ..., n}`.-/ +theorem HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_sum + (h : HasFPowerSeriesWithinOnBall f p s x r) (h' : AnalyticOn 𝕜 f s) + (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (v : Fin n → E) : + iteratedFDerivWithin 𝕜 n f s x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i)) := by + have : iteratedFDerivWithin 𝕜 n f s x + = iteratedFDerivWithin 𝕜 n f (s ∩ EMetric.ball x r) x := + (iteratedFDerivWithin_inter_open EMetric.isOpen_ball (EMetric.mem_ball_self h.r_pos)).symm + rw [this] + apply HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_sum_of_subset + · exact h.mono inter_subset_left + · exact h'.mono inter_subset_left + · exact hs.inter EMetric.isOpen_ball + · exact ⟨hx, EMetric.mem_ball_self h.r_pos⟩ + · exact inter_subset_right + +/-- If a function has a power series in a ball, then its `n`-th iterated derivative is given by +`(v₁, ..., vₙ) ↦ ∑ pₙ (v_{σ (1)}, ..., v_{σ (n)})` where the sum is over all +permutations of `{1, ..., n}`.-/ +theorem HasFPowerSeriesOnBall.iteratedFDeriv_eq_sum + (h : HasFPowerSeriesOnBall f p x r) (h' : AnalyticOn 𝕜 f univ) {n : ℕ} (v : Fin n → E) : + iteratedFDeriv 𝕜 n f x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i)) := by + simp only [← iteratedFDerivWithin_univ, ← hasFPowerSeriesWithinOnBall_univ] at h ⊢ + exact h.iteratedFDerivWithin_eq_sum h' uniqueDiffOn_univ (mem_univ x) v + +/-- If a function has a power series in a ball, then its `n`-th iterated derivative is given by +`(v₁, ..., vₙ) ↦ ∑ pₙ (v_{σ (1)}, ..., v_{σ (n)})` where the sum is over all +permutations of `{1, ..., n}`.-/ +theorem HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_sum_of_completeSpace [CompleteSpace F] + (h : HasFPowerSeriesWithinOnBall f p s x r) + (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (v : Fin n → E) : + iteratedFDerivWithin 𝕜 n f s x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i)) := by + have : iteratedFDerivWithin 𝕜 n f s x + = iteratedFDerivWithin 𝕜 n f (s ∩ EMetric.ball x r) x := + (iteratedFDerivWithin_inter_open EMetric.isOpen_ball (EMetric.mem_ball_self h.r_pos)).symm + rw [this] + apply HasFPowerSeriesWithinOnBall.iteratedFDerivWithin_eq_sum_of_subset + · exact h.mono inter_subset_left + · apply h.analyticOn.mono + rw [insert_eq_of_mem hx] + · exact hs.inter EMetric.isOpen_ball + · exact ⟨hx, EMetric.mem_ball_self h.r_pos⟩ + · exact inter_subset_right + +/-- If a function has a power series in a ball, then its `n`-th iterated derivative is given by +`(v₁, ..., vₙ) ↦ ∑ pₙ (v_{σ (1)}, ..., v_{σ (n)})` where the sum is over all +permutations of `{1, ..., n}`.-/ +theorem HasFPowerSeriesOnBall.iteratedFDeriv_eq_sum_of_completeSpace [CompleteSpace F] + (h : HasFPowerSeriesOnBall f p x r) {n : ℕ} (v : Fin n → E) : + iteratedFDeriv 𝕜 n f x v = ∑ σ : Perm (Fin n), p n (fun i ↦ v (σ i)) := by + simp only [← iteratedFDerivWithin_univ, ← hasFPowerSeriesWithinOnBall_univ] at h ⊢ + exact h.iteratedFDerivWithin_eq_sum_of_completeSpace uniqueDiffOn_univ (mem_univ _) v + +/-- The `n`-th iterated derivative of an analytic function on a set is symmetric. -/ +theorem AnalyticOn.iteratedFDerivWithin_comp_perm + (h : AnalyticOn 𝕜 f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (v : Fin n → E) + (σ : Perm (Fin n)) : + iteratedFDerivWithin 𝕜 n f s x (v ∘ σ) = iteratedFDerivWithin 𝕜 n f s x v := by + rcases h x hx with ⟨p, r, hp⟩ + rw [hp.iteratedFDerivWithin_eq_sum h hs hx, hp.iteratedFDerivWithin_eq_sum h hs hx] + let e := Equiv.mulLeft σ + conv_rhs => rw [← Equiv.sum_comp e] + rfl + +/-- The `n`-th iterated derivative of an analytic function on a set is symmetric. -/ +theorem ContDiffWithinAt.iteratedFDerivWithin_comp_perm + (h : ContDiffWithinAt 𝕜 ω f s x) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {n : ℕ} (v : Fin n → E) + (σ : Perm (Fin n)) : + iteratedFDerivWithin 𝕜 n f s x (v ∘ σ) = iteratedFDerivWithin 𝕜 n f s x v := by + rcases h.contDiffOn' le_rfl (by simp) with ⟨u, u_open, xu, hu⟩ + rw [insert_eq_of_mem hx] at hu + have : iteratedFDerivWithin 𝕜 n f (s ∩ u) x = iteratedFDerivWithin 𝕜 n f s x := + iteratedFDerivWithin_inter_open u_open xu + rw [← this] + exact AnalyticOn.iteratedFDerivWithin_comp_perm hu.analyticOn (hs.inter u_open) ⟨hx, xu⟩ _ _ + +/-- The `n`-th iterated derivative of an analytic function is symmetric. -/ +theorem AnalyticOn.iteratedFDeriv_comp_perm + (h : AnalyticOn 𝕜 f univ) {n : ℕ} (v : Fin n → E) (σ : Perm (Fin n)) : + iteratedFDeriv 𝕜 n f x (v ∘ σ) = iteratedFDeriv 𝕜 n f x v := by + rw [← iteratedFDerivWithin_univ] + exact h.iteratedFDerivWithin_comp_perm uniqueDiffOn_univ (mem_univ x) _ _ + +/-- The `n`-th iterated derivative of an analytic function is symmetric. -/ +theorem ContDiffAt.iteratedFDeriv_comp_perm + (h : ContDiffAt 𝕜 ω f x) {n : ℕ} (v : Fin n → E) (σ : Perm (Fin n)) : + iteratedFDeriv 𝕜 n f x (v ∘ σ) = iteratedFDeriv 𝕜 n f x v := by + rw [← iteratedFDerivWithin_univ] + exact h.iteratedFDerivWithin_comp_perm uniqueDiffOn_univ (mem_univ x) _ _ diff --git a/Mathlib/Analysis/Analytic/OfScalars.lean b/Mathlib/Analysis/Analytic/OfScalars.lean index 688d6468fb486..08114dc0ef413 100644 --- a/Mathlib/Analysis/Analytic/OfScalars.lean +++ b/Mathlib/Analysis/Analytic/OfScalars.lean @@ -62,7 +62,8 @@ variable (𝕜) in theorem ofScalars_series_injective [Nontrivial E] : Function.Injective (ofScalars E (𝕜 := 𝕜)) := by intro _ _ refine Function.mtr fun h ↦ ?_ - simp_rw [FormalMultilinearSeries.ext_iff, ofScalars, ContinuousMultilinearMap.ext_iff, smul_apply] + simp_rw [FormalMultilinearSeries.ext_iff, ofScalars, ContinuousMultilinearMap.ext_iff, + ContinuousMultilinearMap.smul_apply] push_neg obtain ⟨n, hn⟩ := Function.ne_iff.1 h refine ⟨n, fun _ ↦ 1, ?_⟩ diff --git a/Mathlib/Analysis/BoundedVariation.lean b/Mathlib/Analysis/BoundedVariation.lean index 4a2fafb5a8000..74167269753e8 100644 --- a/Mathlib/Analysis/BoundedVariation.lean +++ b/Mathlib/Analysis/BoundedVariation.lean @@ -7,784 +7,32 @@ import Mathlib.Analysis.Calculus.FDeriv.Add import Mathlib.Analysis.Calculus.FDeriv.Equiv import Mathlib.Analysis.Calculus.FDeriv.Prod import Mathlib.Analysis.Calculus.Monotone -import Mathlib.Data.Set.Function -import Mathlib.Algebra.Group.Basic -import Mathlib.Tactic.WLOG +import Mathlib.Topology.EMetricSpace.BoundedVariation /-! -# Functions of bounded variation +# Almost everywhere differentiability of functions with locally bounded variation -We study functions of bounded variation. In particular, we show that a bounded variation function -is a difference of monotone functions, and differentiable almost everywhere. This implies that -Lipschitz functions from the real line into finite-dimensional vector space are also differentiable -almost everywhere. +In this file we show that a bounded variation function is differentiable almost everywhere. +This implies that Lipschitz functions from the real line into finite-dimensional vector space +are also differentiable almost everywhere. ## Main definitions and results -* `eVariationOn f s` is the total variation of the function `f` on the set `s`, in `ℝ≥0∞`. -* `BoundedVariationOn f s` registers that the variation of `f` on `s` is finite. -* `LocallyBoundedVariationOn f s` registers that `f` has finite variation on any compact - subinterval of `s`. -* `variationOnFromTo f s a b` is the signed variation of `f` on `s ∩ Icc a b`, converted to `ℝ`. - -* `eVariationOn.Icc_add_Icc` states that the variation of `f` on `[a, c]` is the sum of its - variations on `[a, b]` and `[b, c]`. -* `LocallyBoundedVariationOn.exists_monotoneOn_sub_monotoneOn` proves that a function - with locally bounded variation is the difference of two monotone functions. -* `LipschitzWith.locallyBoundedVariationOn` shows that a Lipschitz function has locally - bounded variation. * `LocallyBoundedVariationOn.ae_differentiableWithinAt` shows that a bounded variation function into a finite dimensional real vector space is differentiable almost everywhere. * `LipschitzOnWith.ae_differentiableWithinAt` is the same result for Lipschitz functions. We also give several variations around these results. -## Implementation - -We define the variation as an extended nonnegative real, to allow for infinite variation. This makes -it possible to use the complete linear order structure of `ℝ≥0∞`. The proofs would be much -more tedious with an `ℝ`-valued or `ℝ≥0`-valued variation, since one would always need to check -that the sets one uses are nonempty and bounded above as these are only conditionally complete. -/ - -open scoped NNReal ENNReal Topology UniformConvergence - +open scoped NNReal ENNReal Topology open Set MeasureTheory Filter -- Porting note: sectioned variables because a `wlog` was broken due to extra variables in context variable {α : Type*} [LinearOrder α] {E : Type*} [PseudoEMetricSpace E] -/-- The (extended real valued) variation of a function `f` on a set `s` inside a linear order is -the supremum of the sum of `edist (f (u (i+1))) (f (u i))` over all finite increasing -sequences `u` in `s`. -/ -noncomputable def eVariationOn (f : α → E) (s : Set α) : ℝ≥0∞ := - ⨆ p : ℕ × { u : ℕ → α // Monotone u ∧ ∀ i, u i ∈ s }, - ∑ i ∈ Finset.range p.1, edist (f (p.2.1 (i + 1))) (f (p.2.1 i)) - -/-- A function has bounded variation on a set `s` if its total variation there is finite. -/ -def BoundedVariationOn (f : α → E) (s : Set α) := - eVariationOn f s ≠ ∞ - -/-- A function has locally bounded variation on a set `s` if, given any interval `[a, b]` with -endpoints in `s`, then the function has finite variation on `s ∩ [a, b]`. -/ -def LocallyBoundedVariationOn (f : α → E) (s : Set α) := - ∀ a b, a ∈ s → b ∈ s → BoundedVariationOn f (s ∩ Icc a b) - -/-! ## Basic computations of variation -/ - -namespace eVariationOn - -theorem nonempty_monotone_mem {s : Set α} (hs : s.Nonempty) : - Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ s } := by - obtain ⟨x, hx⟩ := hs - exact ⟨⟨fun _ => x, fun i j _ => le_rfl, fun _ => hx⟩⟩ - -theorem eq_of_edist_zero_on {f f' : α → E} {s : Set α} (h : ∀ ⦃x⦄, x ∈ s → edist (f x) (f' x) = 0) : - eVariationOn f s = eVariationOn f' s := by - dsimp only [eVariationOn] - congr 1 with p : 1 - congr 1 with i : 1 - rw [edist_congr_right (h <| p.snd.prop.2 (i + 1)), edist_congr_left (h <| p.snd.prop.2 i)] - -theorem eq_of_eqOn {f f' : α → E} {s : Set α} (h : EqOn f f' s) : - eVariationOn f s = eVariationOn f' s := - eq_of_edist_zero_on fun x xs => by rw [h xs, edist_self] - -theorem sum_le (f : α → E) {s : Set α} (n : ℕ) {u : ℕ → α} (hu : Monotone u) (us : ∀ i, u i ∈ s) : - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := - le_iSup_of_le ⟨n, u, hu, us⟩ le_rfl - -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 ∈ Finset.Ico m n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := by - 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) - calc - ∑ i ∈ Finset.Ico m n, edist (f (u (i + 1))) (f (u i)) - = ∑ i ∈ Finset.Ico m n, edist (f (v (i + 1))) (f (v i)) := - Finset.sum_congr rfl fun i hi ↦ by - rw [Finset.mem_Ico] at hi - simp only [v, π, projIcc_of_mem hmn ⟨hi.1, hi.2.le⟩, - projIcc_of_mem hmn ⟨hi.1.trans i.le_succ, hi.2⟩] - _ ≤ ∑ i ∈ Finset.range n, edist (f (v (i + 1))) (f (v i)) := - Finset.sum_mono_set _ (Nat.Iio_eq_range ▸ Finset.Ico_subset_Iio_self) - _ ≤ eVariationOn f s := - sum_le _ _ (fun i j h ↦ hu (π i).2 (π j).2 (monotone_projIcc hmn h)) fun i ↦ us _ (π i).2 - -theorem sum_le_of_monotoneOn_Iic (f : α → E) {s : Set α} {n : ℕ} {u : ℕ → α} - (hu : MonotoneOn u (Iic n)) (us : ∀ i ≤ n, u i ∈ s) : - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := by - simpa using sum_le_of_monotoneOn_Icc f (m := 0) (hu.mono Icc_subset_Iic_self) fun i hi ↦ us i hi.2 - -theorem mono (f : α → E) {s t : Set α} (hst : t ⊆ s) : eVariationOn f t ≤ eVariationOn f s := by - apply iSup_le _ - rintro ⟨n, ⟨u, hu, ut⟩⟩ - exact sum_le f n hu fun i => hst (ut i) - -theorem _root_.BoundedVariationOn.mono {f : α → E} {s : Set α} (h : BoundedVariationOn f s) - {t : Set α} (ht : t ⊆ s) : BoundedVariationOn f t := - ne_top_of_le_ne_top h (eVariationOn.mono f ht) - -theorem _root_.BoundedVariationOn.locallyBoundedVariationOn {f : α → E} {s : Set α} - (h : BoundedVariationOn f s) : LocallyBoundedVariationOn f s := fun _ _ _ _ => - h.mono inter_subset_left - -theorem edist_le (f : α → E) {s : Set α} {x y : α} (hx : x ∈ s) (hy : y ∈ s) : - edist (f x) (f y) ≤ eVariationOn f s := by - wlog hxy : y ≤ x generalizing x y - · rw [edist_comm] - exact this hy hx (le_of_not_le hxy) - let u : ℕ → α := fun n => if n = 0 then y else x - have hu : Monotone u := monotone_nat_of_le_succ fun - | 0 => hxy - | (_ + 1) => le_rfl - have us : ∀ i, u i ∈ s := fun - | 0 => hy - | (_ + 1) => hx - simpa only [Finset.sum_range_one] using sum_le f 1 hu us - -theorem eq_zero_iff (f : α → E) {s : Set α} : - eVariationOn f s = 0 ↔ ∀ x ∈ s, ∀ y ∈ s, edist (f x) (f y) = 0 := by - constructor - · rintro h x xs y ys - rw [← le_zero_iff, ← h] - exact edist_le f xs ys - · rintro h - dsimp only [eVariationOn] - rw [ENNReal.iSup_eq_zero] - rintro ⟨n, u, um, us⟩ - exact Finset.sum_eq_zero fun i _ => h _ (us i.succ) _ (us i) - -theorem constant_on {f : α → E} {s : Set α} (hf : (f '' s).Subsingleton) : - eVariationOn f s = 0 := by - rw [eq_zero_iff] - rintro x xs y ys - rw [hf ⟨x, xs, rfl⟩ ⟨y, ys, rfl⟩, edist_self] - -@[simp] -protected theorem subsingleton (f : α → E) {s : Set α} (hs : s.Subsingleton) : - eVariationOn f s = 0 := - constant_on (hs.image f) - -theorem lowerSemicontinuous_aux {ι : Type*} {F : ι → α → E} {p : Filter ι} {f : α → E} {s : Set α} - (Ffs : ∀ x ∈ s, Tendsto (fun i => F i x) p (𝓝 (f x))) {v : ℝ≥0∞} (hv : v < eVariationOn f s) : - ∀ᶠ n : ι in p, v < eVariationOn (F n) s := by - obtain ⟨⟨n, ⟨u, um, us⟩⟩, hlt⟩ : - ∃ p : ℕ × { u : ℕ → α // Monotone u ∧ ∀ i, u i ∈ s }, - v < ∑ i ∈ Finset.range p.1, edist (f ((p.2 : ℕ → α) (i + 1))) (f ((p.2 : ℕ → α) i)) := - lt_iSup_iff.mp hv - have : Tendsto (fun j => ∑ i ∈ Finset.range n, edist (F j (u (i + 1))) (F j (u i))) p - (𝓝 (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i)))) := by - apply tendsto_finset_sum - exact fun i _ => Tendsto.edist (Ffs (u i.succ) (us i.succ)) (Ffs (u i) (us i)) - exact (this.eventually_const_lt hlt).mono fun i h => h.trans_le (sum_le (F i) n um us) - -/-- The map `(eVariationOn · s)` is lower semicontinuous for pointwise convergence *on `s`*. -Pointwise convergence on `s` is encoded here as uniform convergence on the family consisting of the -singletons of elements of `s`. --/ -protected theorem lowerSemicontinuous (s : Set α) : - LowerSemicontinuous fun f : α →ᵤ[s.image singleton] E => eVariationOn f s := fun f ↦ by - apply @lowerSemicontinuous_aux _ _ _ _ (UniformOnFun α E (s.image singleton)) id (𝓝 f) f s _ - simpa only [UniformOnFun.tendsto_iff_tendstoUniformlyOn, mem_image, forall_exists_index, and_imp, - forall_apply_eq_imp_iff₂, tendstoUniformlyOn_singleton_iff_tendsto] using @tendsto_id _ (𝓝 f) - -/-- The map `(eVariationOn · s)` is lower semicontinuous for uniform convergence on `s`. -/ -theorem lowerSemicontinuous_uniformOn (s : Set α) : - LowerSemicontinuous fun f : α →ᵤ[{s}] E => eVariationOn f s := fun f ↦ by - apply @lowerSemicontinuous_aux _ _ _ _ (UniformOnFun α E {s}) id (𝓝 f) f s _ - have := @tendsto_id _ (𝓝 f) - rw [UniformOnFun.tendsto_iff_tendstoUniformlyOn] at this - simp_rw [← tendstoUniformlyOn_singleton_iff_tendsto] - exact fun x xs => (this s rfl).mono (singleton_subset_iff.mpr xs) - -theorem _root_.BoundedVariationOn.dist_le {E : Type*} [PseudoMetricSpace E] {f : α → E} - {s : Set α} (h : BoundedVariationOn f s) {x y : α} (hx : x ∈ s) (hy : y ∈ s) : - dist (f x) (f y) ≤ (eVariationOn f s).toReal := by - rw [← ENNReal.ofReal_le_ofReal_iff ENNReal.toReal_nonneg, ENNReal.ofReal_toReal h, ← edist_dist] - exact edist_le f hx hy - -theorem _root_.BoundedVariationOn.sub_le {f : α → ℝ} {s : Set α} (h : BoundedVariationOn f s) - {x y : α} (hx : x ∈ s) (hy : y ∈ s) : f x - f y ≤ (eVariationOn f s).toReal := by - apply (le_abs_self _).trans - rw [← Real.dist_eq] - exact h.dist_le hx hy - -/-- Consider a monotone function `u` parameterizing some points of a set `s`. Given `x ∈ s`, then -one can find another monotone function `v` parameterizing the same points as `u`, with `x` added. -In particular, the variation of a function along `u` is bounded by its variation along `v`. -/ -theorem add_point (f : α → E) {s : Set α} {x : α} (hx : x ∈ s) (u : ℕ → α) (hu : Monotone u) - (us : ∀ i, u i ∈ s) (n : ℕ) : - ∃ (v : ℕ → α) (m : ℕ), Monotone v ∧ (∀ i, v i ∈ s) ∧ x ∈ v '' Iio m ∧ - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ - ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := by - rcases le_or_lt (u n) x with (h | h) - · let v i := if i ≤ n then u i else x - have vs : ∀ i, v i ∈ s := fun i ↦ by - simp only [v] - split_ifs - · exact us i - · exact hx - have hv : Monotone v := by - refine monotone_nat_of_le_succ fun i => ?_ - simp only [v] - rcases lt_trichotomy i n with (hi | rfl | hi) - · have : i + 1 ≤ n := Nat.succ_le_of_lt hi - simp only [hi.le, this, if_true] - exact hu (Nat.le_succ i) - · simp only [le_refl, if_true, add_le_iff_nonpos_right, Nat.le_zero, Nat.one_ne_zero, - if_false, h] - · have A : ¬i ≤ n := hi.not_le - have B : ¬i + 1 ≤ n := fun h => A (i.le_succ.trans h) - simp only [A, B, if_false, le_rfl] - refine ⟨v, n + 2, hv, vs, (mem_image _ _ _).2 ⟨n + 1, ?_, ?_⟩, ?_⟩ - · rw [mem_Iio]; exact Nat.lt_succ_self (n + 1) - · have : ¬n + 1 ≤ n := Nat.not_succ_le_self n - simp only [v, this, ite_eq_right_iff, IsEmpty.forall_iff] - · calc - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = - ∑ i ∈ Finset.range n, edist (f (v (i + 1))) (f (v i)) := by - apply Finset.sum_congr rfl fun i hi => ?_ - simp only [Finset.mem_range] at hi - have : i + 1 ≤ n := Nat.succ_le_of_lt hi - simp only [v, hi.le, this, if_true] - _ ≤ ∑ j ∈ Finset.range (n + 2), edist (f (v (j + 1))) (f (v j)) := - Finset.sum_le_sum_of_subset (Finset.range_mono (Nat.le_add_right n 2)) - have exists_N : ∃ N, N ≤ n ∧ x < u N := ⟨n, le_rfl, h⟩ - let N := Nat.find exists_N - have hN : N ≤ n ∧ x < u N := Nat.find_spec exists_N - let w : ℕ → α := fun i => if i < N then u i else if i = N then x else u (i - 1) - have ws : ∀ i, w i ∈ s := by - dsimp only [w] - intro i - split_ifs - exacts [us _, hx, us _] - have hw : Monotone w := by - apply monotone_nat_of_le_succ fun i => ?_ - dsimp only [w] - rcases lt_trichotomy (i + 1) N with (hi | hi | hi) - · have : i < N := Nat.lt_of_le_of_lt (Nat.le_succ i) hi - simp only [hi, this, if_true] - exact hu (Nat.le_succ _) - · have A : i < N := hi ▸ i.lt_succ_self - have B : ¬i + 1 < N := by rw [← hi]; exact fun h => h.ne rfl - rw [if_pos A, if_neg B, if_pos hi] - have T := Nat.find_min exists_N A - push_neg at T - exact T (A.le.trans hN.1) - · have A : ¬i < N := (Nat.lt_succ_iff.mp hi).not_lt - have B : ¬i + 1 < N := hi.not_lt - have C : ¬i + 1 = N := hi.ne.symm - have D : i + 1 - 1 = i := Nat.pred_succ i - rw [if_neg A, if_neg B, if_neg C, D] - split_ifs - · exact hN.2.le.trans (hu (le_of_not_lt A)) - · exact hu (Nat.pred_le _) - refine ⟨w, n + 1, hw, ws, (mem_image _ _ _).2 ⟨N, hN.1.trans_lt (Nat.lt_succ_self n), ?_⟩, ?_⟩ - · dsimp only [w]; rw [if_neg (lt_irrefl N), if_pos rfl] - rcases eq_or_lt_of_le (zero_le N) with (Npos | Npos) - · calc - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = - ∑ i ∈ Finset.range n, edist (f (w (1 + i + 1))) (f (w (1 + i))) := by - apply Finset.sum_congr rfl fun i _hi => ?_ - dsimp only [w] - simp only [← Npos, Nat.not_lt_zero, Nat.add_succ_sub_one, add_zero, if_false, - add_eq_zero, Nat.one_ne_zero, false_and, Nat.succ_add_sub_one, zero_add] - rw [add_comm 1 i] - _ = ∑ i ∈ Finset.Ico 1 (n + 1), edist (f (w (i + 1))) (f (w i)) := by - rw [Finset.range_eq_Ico] - exact Finset.sum_Ico_add (fun i => edist (f (w (i + 1))) (f (w i))) 0 n 1 - _ ≤ ∑ j ∈ Finset.range (n + 1), edist (f (w (j + 1))) (f (w j)) := by - apply Finset.sum_le_sum_of_subset _ - rw [Finset.range_eq_Ico] - exact Finset.Ico_subset_Ico zero_le_one le_rfl - · calc - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = - ((∑ i ∈ Finset.Ico 0 (N - 1), edist (f (u (i + 1))) (f (u i))) + - ∑ i ∈ Finset.Ico (N - 1) N, edist (f (u (i + 1))) (f (u i))) + - ∑ i ∈ Finset.Ico N n, edist (f (u (i + 1))) (f (u i)) := by - rw [Finset.sum_Ico_consecutive, Finset.sum_Ico_consecutive, Finset.range_eq_Ico] - · exact zero_le _ - · exact hN.1 - · exact zero_le _ - · exact Nat.pred_le _ - _ = (∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + - edist (f (u N)) (f (u (N - 1))) + - ∑ i ∈ Finset.Ico N n, edist (f (w (1 + i + 1))) (f (w (1 + i))) := by - congr 1 - · congr 1 - · apply Finset.sum_congr rfl fun i hi => ?_ - simp only [Finset.mem_Ico, zero_le', true_and] at hi - dsimp only [w] - have A : i + 1 < N := Nat.lt_pred_iff.1 hi - have B : i < N := Nat.lt_of_succ_lt A - rw [if_pos A, if_pos B] - · have A : N - 1 + 1 = N := Nat.succ_pred_eq_of_pos Npos - have : Finset.Ico (N - 1) N = {N - 1} := by rw [← Nat.Ico_succ_singleton, A] - simp only [this, A, Finset.sum_singleton] - · apply Finset.sum_congr rfl fun i hi => ?_ - rw [Finset.mem_Ico] at hi - dsimp only [w] - have A : ¬1 + i + 1 < N := by omega - have B : ¬1 + i + 1 = N := by omega - have C : ¬1 + i < N := by omega - have D : ¬1 + i = N := by omega - rw [if_neg A, if_neg B, if_neg C, if_neg D] - congr 3 <;> · rw [add_comm, Nat.sub_one]; apply Nat.pred_succ - _ = (∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + - edist (f (w (N + 1))) (f (w (N - 1))) + - ∑ i ∈ Finset.Ico (N + 1) (n + 1), edist (f (w (i + 1))) (f (w i)) := by - congr 1 - · congr 1 - · dsimp only [w] - have A : ¬N + 1 < N := Nat.not_succ_lt_self - have B : N - 1 < N := Nat.pred_lt Npos.ne' - simp only [A, not_and, not_lt, Nat.succ_ne_self, Nat.add_succ_sub_one, add_zero, - if_false, B, if_true] - · exact Finset.sum_Ico_add (fun i => edist (f (w (i + 1))) (f (w i))) N n 1 - _ ≤ ((∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + - ∑ i ∈ Finset.Ico (N - 1) (N + 1), edist (f (w (i + 1))) (f (w i))) + - ∑ i ∈ Finset.Ico (N + 1) (n + 1), edist (f (w (i + 1))) (f (w i)) := by - refine add_le_add (add_le_add le_rfl ?_) le_rfl - have A : N - 1 + 1 = N := Nat.succ_pred_eq_of_pos Npos - have B : N - 1 + 1 < N + 1 := A.symm ▸ N.lt_succ_self - have C : N - 1 < N + 1 := lt_of_le_of_lt N.pred_le N.lt_succ_self - rw [Finset.sum_eq_sum_Ico_succ_bot C, Finset.sum_eq_sum_Ico_succ_bot B, A, Finset.Ico_self, - Finset.sum_empty, add_zero, add_comm (edist _ _)] - exact edist_triangle _ _ _ - _ = ∑ j ∈ Finset.range (n + 1), edist (f (w (j + 1))) (f (w j)) := by - rw [Finset.sum_Ico_consecutive, Finset.sum_Ico_consecutive, Finset.range_eq_Ico] - · exact zero_le _ - · exact Nat.succ_le_succ hN.left - · exact zero_le _ - · exact N.pred_le.trans N.le_succ - -/-- The variation of a function on the union of two sets `s` and `t`, with `s` to the left of `t`, -bounds the sum of the variations along `s` and `t`. -/ -theorem add_le_union (f : α → E) {s t : Set α} (h : ∀ x ∈ s, ∀ y ∈ t, x ≤ y) : - eVariationOn f s + eVariationOn f t ≤ eVariationOn f (s ∪ t) := by - by_cases hs : s = ∅ - · simp [hs] - have : Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ s } := - nonempty_monotone_mem (nonempty_iff_ne_empty.2 hs) - by_cases ht : t = ∅ - · simp [ht] - have : Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ t } := - nonempty_monotone_mem (nonempty_iff_ne_empty.2 ht) - refine ENNReal.iSup_add_iSup_le ?_ - /- We start from two sequences `u` and `v` along `s` and `t` respectively, and we build a new - sequence `w` along `s ∪ t` by juxtaposing them. Its variation is larger than the sum of the - variations. -/ - rintro ⟨n, ⟨u, hu, us⟩⟩ ⟨m, ⟨v, hv, vt⟩⟩ - let w i := if i ≤ n then u i else v (i - (n + 1)) - have wst : ∀ i, w i ∈ s ∪ t := by - intro i - by_cases hi : i ≤ n - · simp [w, hi, us] - · simp [w, hi, vt] - have hw : Monotone w := by - intro i j hij - dsimp only [w] - split_ifs with h_1 h_2 h_2 - · exact hu hij - · apply h _ (us _) _ (vt _) - · exfalso; exact h_1 (hij.trans h_2) - · apply hv (tsub_le_tsub hij le_rfl) - calc - ((∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) + - ∑ i ∈ Finset.range m, edist (f (v (i + 1))) (f (v i))) = - (∑ i ∈ Finset.range n, edist (f (w (i + 1))) (f (w i))) + - ∑ i ∈ Finset.range m, edist (f (w (n + 1 + i + 1))) (f (w (n + 1 + i))) := by - dsimp only [w] - congr 1 - · refine Finset.sum_congr rfl fun i hi => ?_ - simp only [Finset.mem_range] at hi - have : i + 1 ≤ n := Nat.succ_le_of_lt hi - simp [hi.le, this] - · refine Finset.sum_congr rfl fun i hi => ?_ - simp only [Finset.mem_range] at hi - have B : ¬n + 1 + i ≤ n := by omega - have A : ¬n + 1 + i + 1 ≤ n := fun h => B ((n + 1 + i).le_succ.trans h) - have C : n + 1 + i - n = i + 1 := by - rw [tsub_eq_iff_eq_add_of_le] - · abel - · exact n.le_succ.trans (n.succ.le_add_right i) - simp only [A, B, C, Nat.succ_sub_succ_eq_sub, if_false, add_tsub_cancel_left] - _ = (∑ i ∈ Finset.range n, edist (f (w (i + 1))) (f (w i))) + - ∑ i ∈ Finset.Ico (n + 1) (n + 1 + m), edist (f (w (i + 1))) (f (w i)) := by - congr 1 - rw [Finset.range_eq_Ico] - convert Finset.sum_Ico_add (fun i : ℕ => edist (f (w (i + 1))) (f (w i))) 0 m (n + 1) - using 3 <;> abel - _ ≤ ∑ i ∈ Finset.range (n + 1 + m), edist (f (w (i + 1))) (f (w i)) := by - rw [← Finset.sum_union] - · apply Finset.sum_le_sum_of_subset _ - rintro i hi - simp only [Finset.mem_union, Finset.mem_range, Finset.mem_Ico] at hi ⊢ - cases' hi with hi hi - · exact lt_of_lt_of_le hi (n.le_succ.trans (n.succ.le_add_right m)) - · exact hi.2 - · refine Finset.disjoint_left.2 fun i hi h'i => ?_ - simp only [Finset.mem_Ico, Finset.mem_range] at hi h'i - exact hi.not_lt (Nat.lt_of_succ_le h'i.left) - _ ≤ eVariationOn f (s ∪ t) := sum_le f _ hw wst - -/-- If a set `s` is to the left of a set `t`, and both contain the boundary point `x`, then -the variation of `f` along `s ∪ t` is the sum of the variations. -/ -theorem union (f : α → E) {s t : Set α} {x : α} (hs : IsGreatest s x) (ht : IsLeast t x) : - eVariationOn f (s ∪ t) = eVariationOn f s + eVariationOn f t := by - classical - apply le_antisymm _ (eVariationOn.add_le_union f fun a ha b hb => le_trans (hs.2 ha) (ht.2 hb)) - apply iSup_le _ - rintro ⟨n, ⟨u, hu, ust⟩⟩ - obtain ⟨v, m, hv, vst, xv, huv⟩ : ∃ (v : ℕ → α) (m : ℕ), - Monotone v ∧ (∀ i, v i ∈ s ∪ t) ∧ x ∈ v '' Iio m ∧ - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ - ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := - eVariationOn.add_point f (mem_union_left t hs.1) u hu ust n - obtain ⟨N, hN, Nx⟩ : ∃ N, N < m ∧ v N = x := xv - calc - (∑ j ∈ Finset.range n, edist (f (u (j + 1))) (f (u j))) ≤ - ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := - huv - _ = (∑ j ∈ Finset.Ico 0 N, edist (f (v (j + 1))) (f (v j))) + - ∑ j ∈ Finset.Ico N m, edist (f (v (j + 1))) (f (v j)) := by - rw [Finset.range_eq_Ico, Finset.sum_Ico_consecutive _ (zero_le _) hN.le] - _ ≤ eVariationOn f s + eVariationOn f t := by - refine add_le_add ?_ ?_ - · apply sum_le_of_monotoneOn_Icc _ (hv.monotoneOn _) fun i hi => ?_ - rcases vst i with (h | h); · exact h - have : v i = x := by - apply le_antisymm - · rw [← Nx]; exact hv hi.2 - · exact ht.2 h - rw [this] - exact hs.1 - · apply sum_le_of_monotoneOn_Icc _ (hv.monotoneOn _) fun i hi => ?_ - rcases vst i with (h | h); swap; · exact h - have : v i = x := by - apply le_antisymm - · exact hs.2 h - · rw [← Nx]; exact hv hi.1 - rw [this] - exact ht.1 - -theorem Icc_add_Icc (f : α → E) {s : Set α} {a b c : α} (hab : a ≤ b) (hbc : b ≤ c) (hb : b ∈ s) : - eVariationOn f (s ∩ Icc a b) + eVariationOn f (s ∩ Icc b c) = eVariationOn f (s ∩ Icc a c) := by - have A : IsGreatest (s ∩ Icc a b) b := - ⟨⟨hb, hab, le_rfl⟩, inter_subset_right.trans Icc_subset_Iic_self⟩ - have B : IsLeast (s ∩ Icc b c) b := - ⟨⟨hb, le_rfl, hbc⟩, inter_subset_right.trans Icc_subset_Ici_self⟩ - rw [← eVariationOn.union f A B, ← inter_union_distrib_left, Icc_union_Icc_eq_Icc hab hbc] - -section Monotone - -variable {β : Type*} [LinearOrder β] - -theorem comp_le_of_monotoneOn (f : α → E) {s : Set α} {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) - (φst : MapsTo φ t s) : eVariationOn (f ∘ φ) t ≤ eVariationOn f s := - iSup_le fun ⟨n, u, hu, ut⟩ => - le_iSup_of_le ⟨n, φ ∘ u, fun x y xy => hφ (ut x) (ut y) (hu xy), fun i => φst (ut i)⟩ le_rfl - -theorem comp_le_of_antitoneOn (f : α → E) {s : Set α} {t : Set β} (φ : β → α) (hφ : AntitoneOn φ t) - (φst : MapsTo φ t s) : eVariationOn (f ∘ φ) t ≤ eVariationOn f s := by - refine iSup_le ?_ - rintro ⟨n, u, hu, ut⟩ - rw [← Finset.sum_range_reflect] - refine (Finset.sum_congr rfl fun x hx => ?_).trans_le <| le_iSup_of_le - ⟨n, fun i => φ (u <| n - i), fun x y xy => hφ (ut _) (ut _) (hu <| Nat.sub_le_sub_left xy n), - fun i => φst (ut _)⟩ - le_rfl - rw [Finset.mem_range] at hx - dsimp only [Subtype.coe_mk, Function.comp_apply] - rw [edist_comm] - congr 4 <;> omega - -theorem comp_eq_of_monotoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) : - eVariationOn (f ∘ φ) t = eVariationOn f (φ '' t) := by - apply le_antisymm (comp_le_of_monotoneOn f φ hφ (mapsTo_image φ t)) - cases isEmpty_or_nonempty β - · convert zero_le (_ : ℝ≥0∞) - exact eVariationOn.subsingleton f <| - (subsingleton_of_subsingleton.image _).anti (surjOn_image φ t) - let ψ := φ.invFunOn t - have ψφs : EqOn (φ ∘ ψ) id (φ '' t) := (surjOn_image φ t).rightInvOn_invFunOn - have ψts : MapsTo ψ (φ '' t) t := (surjOn_image φ t).mapsTo_invFunOn - have hψ : MonotoneOn ψ (φ '' t) := Function.monotoneOn_of_rightInvOn_of_mapsTo hφ ψφs ψts - change eVariationOn (f ∘ id) (φ '' t) ≤ eVariationOn (f ∘ φ) t - rw [← eq_of_eqOn (ψφs.comp_left : EqOn (f ∘ φ ∘ ψ) (f ∘ id) (φ '' t))] - exact comp_le_of_monotoneOn _ ψ hψ ψts - -theorem comp_inter_Icc_eq_of_monotoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) - {x y : β} (hx : x ∈ t) (hy : y ∈ t) : - eVariationOn (f ∘ φ) (t ∩ Icc x y) = eVariationOn f (φ '' t ∩ Icc (φ x) (φ y)) := by - rcases le_total x y with (h | h) - · convert comp_eq_of_monotoneOn f φ (hφ.mono Set.inter_subset_left) - apply le_antisymm - · rintro _ ⟨⟨u, us, rfl⟩, vφx, vφy⟩ - rcases le_total x u with (xu | ux) - · rcases le_total u y with (uy | yu) - · exact ⟨u, ⟨us, ⟨xu, uy⟩⟩, rfl⟩ - · rw [le_antisymm vφy (hφ hy us yu)] - exact ⟨y, ⟨hy, ⟨h, le_rfl⟩⟩, rfl⟩ - · rw [← le_antisymm vφx (hφ us hx ux)] - exact ⟨x, ⟨hx, ⟨le_rfl, h⟩⟩, rfl⟩ - · rintro _ ⟨u, ⟨⟨hu, xu, uy⟩, rfl⟩⟩ - exact ⟨⟨u, hu, rfl⟩, ⟨hφ hx hu xu, hφ hu hy uy⟩⟩ - · rw [eVariationOn.subsingleton, eVariationOn.subsingleton] - exacts [(Set.subsingleton_Icc_of_ge (hφ hy hx h)).anti Set.inter_subset_right, - (Set.subsingleton_Icc_of_ge h).anti Set.inter_subset_right] - -theorem comp_eq_of_antitoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : AntitoneOn φ t) : - eVariationOn (f ∘ φ) t = eVariationOn f (φ '' t) := by - apply le_antisymm (comp_le_of_antitoneOn f φ hφ (mapsTo_image φ t)) - cases isEmpty_or_nonempty β - · convert zero_le (_ : ℝ≥0∞) - exact eVariationOn.subsingleton f <| (subsingleton_of_subsingleton.image _).anti - (surjOn_image φ t) - let ψ := φ.invFunOn t - have ψφs : EqOn (φ ∘ ψ) id (φ '' t) := (surjOn_image φ t).rightInvOn_invFunOn - have ψts := (surjOn_image φ t).mapsTo_invFunOn - have hψ : AntitoneOn ψ (φ '' t) := Function.antitoneOn_of_rightInvOn_of_mapsTo hφ ψφs ψts - change eVariationOn (f ∘ id) (φ '' t) ≤ eVariationOn (f ∘ φ) t - rw [← eq_of_eqOn (ψφs.comp_left : EqOn (f ∘ φ ∘ ψ) (f ∘ id) (φ '' t))] - exact comp_le_of_antitoneOn _ ψ hψ ψts - -open OrderDual - -theorem comp_ofDual (f : α → E) (s : Set α) : - eVariationOn (f ∘ ofDual) (ofDual ⁻¹' s) = eVariationOn f s := by - convert comp_eq_of_antitoneOn f ofDual fun _ _ _ _ => id - simp only [Equiv.image_preimage] - -end Monotone - -end eVariationOn - -/-! ## Monotone functions and bounded variation -/ - -theorem MonotoneOn.eVariationOn_le {f : α → ℝ} {s : Set α} (hf : MonotoneOn f s) {a b : α} - (as : a ∈ s) (bs : b ∈ s) : eVariationOn f (s ∩ Icc a b) ≤ ENNReal.ofReal (f b - f a) := by - apply iSup_le _ - rintro ⟨n, ⟨u, hu, us⟩⟩ - calc - (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = - ∑ i ∈ Finset.range n, ENNReal.ofReal (f (u (i + 1)) - f (u i)) := by - refine Finset.sum_congr rfl fun i hi => ?_ - simp only [Finset.mem_range] at hi - rw [edist_dist, Real.dist_eq, abs_of_nonneg] - exact sub_nonneg_of_le (hf (us i).1 (us (i + 1)).1 (hu (Nat.le_succ _))) - _ = ENNReal.ofReal (∑ i ∈ Finset.range n, (f (u (i + 1)) - f (u i))) := by - rw [ENNReal.ofReal_sum_of_nonneg] - intro i _ - exact sub_nonneg_of_le (hf (us i).1 (us (i + 1)).1 (hu (Nat.le_succ _))) - _ = ENNReal.ofReal (f (u n) - f (u 0)) := by rw [Finset.sum_range_sub fun i => f (u i)] - _ ≤ ENNReal.ofReal (f b - f a) := by - apply ENNReal.ofReal_le_ofReal - exact sub_le_sub (hf (us n).1 bs (us n).2.2) (hf as (us 0).1 (us 0).2.1) - -theorem MonotoneOn.locallyBoundedVariationOn {f : α → ℝ} {s : Set α} (hf : MonotoneOn f s) : - LocallyBoundedVariationOn f s := fun _ _ as bs => - ((hf.eVariationOn_le as bs).trans_lt ENNReal.ofReal_lt_top).ne - -/-- The **signed** variation of `f` on the interval `Icc a b` intersected with the set `s`, -squashed to a real (therefore only really meaningful if the variation is finite) --/ -noncomputable def variationOnFromTo (f : α → E) (s : Set α) (a b : α) : ℝ := - if a ≤ b then (eVariationOn f (s ∩ Icc a b)).toReal else -(eVariationOn f (s ∩ Icc b a)).toReal - -namespace variationOnFromTo - -variable (f : α → E) (s : Set α) - -protected theorem self (a : α) : variationOnFromTo f s a a = 0 := by - dsimp only [variationOnFromTo] - rw [if_pos le_rfl, Icc_self, eVariationOn.subsingleton, ENNReal.zero_toReal] - exact fun x hx y hy => hx.2.trans hy.2.symm - -protected theorem nonneg_of_le {a b : α} (h : a ≤ b) : 0 ≤ variationOnFromTo f s a b := by - simp only [variationOnFromTo, if_pos h, ENNReal.toReal_nonneg] - -protected theorem eq_neg_swap (a b : α) : - variationOnFromTo f s a b = -variationOnFromTo f s b a := by - rcases lt_trichotomy a b with (ab | rfl | ba) - · simp only [variationOnFromTo, if_pos ab.le, if_neg ab.not_le, neg_neg] - · simp only [variationOnFromTo.self, neg_zero] - · simp only [variationOnFromTo, if_pos ba.le, if_neg ba.not_le, neg_neg] - -protected theorem nonpos_of_ge {a b : α} (h : b ≤ a) : variationOnFromTo f s a b ≤ 0 := by - rw [variationOnFromTo.eq_neg_swap] - exact neg_nonpos_of_nonneg (variationOnFromTo.nonneg_of_le f s h) - -protected theorem eq_of_le {a b : α} (h : a ≤ b) : - variationOnFromTo f s a b = (eVariationOn f (s ∩ Icc a b)).toReal := - if_pos h - -protected theorem eq_of_ge {a b : α} (h : b ≤ a) : - variationOnFromTo f s a b = -(eVariationOn f (s ∩ Icc b a)).toReal := by - rw [variationOnFromTo.eq_neg_swap, neg_inj, variationOnFromTo.eq_of_le f s h] - -protected theorem add {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) {a b c : α} - (ha : a ∈ s) (hb : b ∈ s) (hc : c ∈ s) : - variationOnFromTo f s a b + variationOnFromTo f s b c = variationOnFromTo f s a c := by - symm - refine additive_of_isTotal ((· : α) ≤ ·) (variationOnFromTo f s) (· ∈ s) ?_ ?_ ha hb hc - · rintro x y _xs _ys - simp only [variationOnFromTo.eq_neg_swap f s y x, Subtype.coe_mk, add_neg_cancel, - forall_true_left] - · rintro x y z xy yz xs ys zs - rw [variationOnFromTo.eq_of_le f s xy, variationOnFromTo.eq_of_le f s yz, - variationOnFromTo.eq_of_le f s (xy.trans yz), - ← ENNReal.toReal_add (hf x y xs ys) (hf y z ys zs), eVariationOn.Icc_add_Icc f xy yz ys] - -variable {f s} in -protected theorem edist_zero_of_eq_zero (hf : LocallyBoundedVariationOn f s) - {a b : α} (ha : a ∈ s) (hb : b ∈ s) (h : variationOnFromTo f s a b = 0) : - edist (f a) (f b) = 0 := by - wlog h' : a ≤ b - · rw [edist_comm] - apply this hf hb ha _ (le_of_not_le h') - rw [variationOnFromTo.eq_neg_swap, h, neg_zero] - · apply le_antisymm _ (zero_le _) - rw [← ENNReal.ofReal_zero, ← h, variationOnFromTo.eq_of_le f s h', - ENNReal.ofReal_toReal (hf a b ha hb)] - apply eVariationOn.edist_le - exacts [⟨ha, ⟨le_rfl, h'⟩⟩, ⟨hb, ⟨h', le_rfl⟩⟩] - -protected theorem eq_left_iff {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) - {a b c : α} (ha : a ∈ s) (hb : b ∈ s) (hc : c ∈ s) : - variationOnFromTo f s a b = variationOnFromTo f s a c ↔ variationOnFromTo f s b c = 0 := by - simp only [← variationOnFromTo.add hf ha hb hc, self_eq_add_right] - -protected theorem eq_zero_iff_of_le {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) - {a b : α} (ha : a ∈ s) (hb : b ∈ s) (ab : a ≤ b) : - variationOnFromTo f s a b = 0 ↔ - ∀ ⦃x⦄ (_hx : x ∈ s ∩ Icc a b) ⦃y⦄ (_hy : y ∈ s ∩ Icc a b), edist (f x) (f y) = 0 := by - rw [variationOnFromTo.eq_of_le _ _ ab, ENNReal.toReal_eq_zero_iff, or_iff_left (hf a b ha hb), - eVariationOn.eq_zero_iff] - -protected theorem eq_zero_iff_of_ge {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) - {a b : α} (ha : a ∈ s) (hb : b ∈ s) (ba : b ≤ a) : - variationOnFromTo f s a b = 0 ↔ - ∀ ⦃x⦄ (_hx : x ∈ s ∩ Icc b a) ⦃y⦄ (_hy : y ∈ s ∩ Icc b a), edist (f x) (f y) = 0 := by - rw [variationOnFromTo.eq_of_ge _ _ ba, neg_eq_zero, ENNReal.toReal_eq_zero_iff, - or_iff_left (hf b a hb ha), eVariationOn.eq_zero_iff] - -protected theorem eq_zero_iff {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) {a b : α} - (ha : a ∈ s) (hb : b ∈ s) : - variationOnFromTo f s a b = 0 ↔ - ∀ ⦃x⦄ (_hx : x ∈ s ∩ uIcc a b) ⦃y⦄ (_hy : y ∈ s ∩ uIcc a b), edist (f x) (f y) = 0 := by - rcases le_total a b with (ab | ba) - · rw [uIcc_of_le ab] - exact variationOnFromTo.eq_zero_iff_of_le hf ha hb ab - · rw [uIcc_of_ge ba] - exact variationOnFromTo.eq_zero_iff_of_ge hf ha hb ba - -variable {f} {s} - -protected theorem monotoneOn (hf : LocallyBoundedVariationOn f s) {a : α} (as : a ∈ s) : - MonotoneOn (variationOnFromTo f s a) s := by - rintro b bs c cs bc - rw [← variationOnFromTo.add hf as bs cs] - exact le_add_of_nonneg_right (variationOnFromTo.nonneg_of_le f s bc) - -protected theorem antitoneOn (hf : LocallyBoundedVariationOn f s) {b : α} (bs : b ∈ s) : - AntitoneOn (fun a => variationOnFromTo f s a b) s := by - rintro a as c cs ac - dsimp only - rw [← variationOnFromTo.add hf as cs bs] - exact le_add_of_nonneg_left (variationOnFromTo.nonneg_of_le f s ac) - -protected theorem sub_self_monotoneOn {f : α → ℝ} {s : Set α} (hf : LocallyBoundedVariationOn f s) - {a : α} (as : a ∈ s) : MonotoneOn (variationOnFromTo f s a - f) s := by - rintro b bs c cs bc - rw [Pi.sub_apply, Pi.sub_apply, le_sub_iff_add_le, add_comm_sub, ← le_sub_iff_add_le'] - calc - f c - f b ≤ |f c - f b| := le_abs_self _ - _ = dist (f b) (f c) := by rw [dist_comm, Real.dist_eq] - _ ≤ variationOnFromTo f s b c := by - rw [variationOnFromTo.eq_of_le f s bc, dist_edist] - apply ENNReal.toReal_mono (hf b c bs cs) - apply eVariationOn.edist_le f - exacts [⟨bs, le_rfl, bc⟩, ⟨cs, bc, le_rfl⟩] - _ = variationOnFromTo f s a c - variationOnFromTo f s a b := by - rw [← variationOnFromTo.add hf as bs cs, add_sub_cancel_left] - -protected theorem comp_eq_of_monotoneOn {β : Type*} [LinearOrder β] (f : α → E) {t : Set β} - (φ : β → α) (hφ : MonotoneOn φ t) {x y : β} (hx : x ∈ t) (hy : y ∈ t) : - variationOnFromTo (f ∘ φ) t x y = variationOnFromTo f (φ '' t) (φ x) (φ y) := by - rcases le_total x y with (h | h) - · rw [variationOnFromTo.eq_of_le _ _ h, variationOnFromTo.eq_of_le _ _ (hφ hx hy h), - eVariationOn.comp_inter_Icc_eq_of_monotoneOn f φ hφ hx hy] - · rw [variationOnFromTo.eq_of_ge _ _ h, variationOnFromTo.eq_of_ge _ _ (hφ hy hx h), - eVariationOn.comp_inter_Icc_eq_of_monotoneOn f φ hφ hy hx] - -end variationOnFromTo - -/-- If a real valued function has bounded variation on a set, then it is a difference of monotone -functions there. -/ -theorem LocallyBoundedVariationOn.exists_monotoneOn_sub_monotoneOn {f : α → ℝ} {s : Set α} - (h : LocallyBoundedVariationOn f s) : - ∃ p q : α → ℝ, MonotoneOn p s ∧ MonotoneOn q s ∧ f = p - q := by - rcases eq_empty_or_nonempty s with (rfl | ⟨c, cs⟩) - · exact ⟨f, 0, subsingleton_empty.monotoneOn _, subsingleton_empty.monotoneOn _, - (sub_zero f).symm⟩ - · exact ⟨_, _, variationOnFromTo.monotoneOn h cs, variationOnFromTo.sub_self_monotoneOn h cs, - (sub_sub_cancel _ _).symm⟩ - -/-! ## Lipschitz functions and bounded variation -/ - -section LipschitzOnWith - -variable {F : Type*} [PseudoEMetricSpace F] - -theorem LipschitzOnWith.comp_eVariationOn_le {f : E → F} {C : ℝ≥0} {t : Set E} - (h : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) : - eVariationOn (f ∘ g) s ≤ C * eVariationOn g s := by - apply iSup_le _ - rintro ⟨n, ⟨u, hu, us⟩⟩ - calc - (∑ i ∈ Finset.range n, edist (f (g (u (i + 1)))) (f (g (u i)))) ≤ - ∑ i ∈ Finset.range n, C * edist (g (u (i + 1))) (g (u i)) := - Finset.sum_le_sum fun i _ => h (hg (us _)) (hg (us _)) - _ = C * ∑ i ∈ Finset.range n, edist (g (u (i + 1))) (g (u i)) := by rw [Finset.mul_sum] - _ ≤ C * eVariationOn g s := mul_le_mul_left' (eVariationOn.sum_le _ _ hu us) _ - -theorem LipschitzOnWith.comp_boundedVariationOn {f : E → F} {C : ℝ≥0} {t : Set E} - (hf : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) - (h : BoundedVariationOn g s) : BoundedVariationOn (f ∘ g) s := - ne_top_of_le_ne_top (ENNReal.mul_ne_top ENNReal.coe_ne_top h) (hf.comp_eVariationOn_le hg) - -theorem LipschitzOnWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥0} {t : Set E} - (hf : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) - (h : LocallyBoundedVariationOn g s) : LocallyBoundedVariationOn (f ∘ g) s := - fun x y xs ys => - hf.comp_boundedVariationOn (hg.mono_left inter_subset_left) (h x y xs ys) - -theorem LipschitzWith.comp_boundedVariationOn {f : E → F} {C : ℝ≥0} (hf : LipschitzWith C f) - {g : α → E} {s : Set α} (h : BoundedVariationOn g s) : BoundedVariationOn (f ∘ g) s := - hf.lipschitzOnWith.comp_boundedVariationOn (mapsTo_univ _ _) h - -theorem LipschitzWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥0} - (hf : LipschitzWith C f) {g : α → E} {s : Set α} (h : LocallyBoundedVariationOn g s) : - LocallyBoundedVariationOn (f ∘ g) s := - hf.lipschitzOnWith.comp_locallyBoundedVariationOn (mapsTo_univ _ _) h - -theorem LipschitzOnWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} {s : Set ℝ} - (hf : LipschitzOnWith C f s) : LocallyBoundedVariationOn f s := - hf.comp_locallyBoundedVariationOn (mapsTo_id _) - (@monotoneOn_id ℝ _ s).locallyBoundedVariationOn - -theorem LipschitzWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} (hf : LipschitzWith C f) - (s : Set ℝ) : LocallyBoundedVariationOn f s := - hf.lipschitzOnWith.locallyBoundedVariationOn - -end LipschitzOnWith - -/-! ## Almost everywhere differentiability of functions with locally bounded variation -/ +/-! ## -/ variable {V : Type*} [NormedAddCommGroup V] [NormedSpace ℝ V] [FiniteDimensional ℝ V] diff --git a/Mathlib/Analysis/BoxIntegral/Box/Basic.lean b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean index fa0d86469c73b..622d8b9eb3b5d 100644 --- a/Mathlib/Analysis/BoxIntegral/Box/Basic.lean +++ b/Mathlib/Analysis/BoxIntegral/Box/Basic.lean @@ -357,7 +357,7 @@ def face {n} (I : Box (Fin (n + 1))) (i : Fin (n + 1)) : Box (Fin n) := theorem face_mk {n} (l u : Fin (n + 1) → ℝ) (h : ∀ i, l i < u i) (i : Fin (n + 1)) : face ⟨l, u, h⟩ i = ⟨l ∘ Fin.succAbove i, u ∘ Fin.succAbove i, fun _ ↦ h _⟩ := rfl -@[mono] +@[gcongr, mono] theorem face_mono {n} {I J : Box (Fin (n + 1))} (h : I ≤ J) (i : Fin (n + 1)) : face I i ≤ face J i := fun _ hx _ ↦ Ioc_subset_Ioc ((le_iff_bounds.1 h).1 _) ((le_iff_bounds.1 h).2 _) (hx _) diff --git a/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean b/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean index c1b1d7ea49571..f9ca9c7272245 100644 --- a/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean +++ b/Mathlib/Analysis/BoxIntegral/Partition/Filter.lean @@ -408,19 +408,19 @@ nonrec theorem RCond.min {ι : Type*} {r₁ r₂ : (ι → ℝ) → Ioi (0 : ℝ (h₂ : l.RCond r₂) : l.RCond fun x => min (r₁ x) (r₂ x) := fun hR x => congr_arg₂ min (h₁ hR x) (h₂ hR x) -@[mono] +@[gcongr, mono] theorem toFilterDistortion_mono (I : Box ι) (h : l₁ ≤ l₂) (hc : c₁ ≤ c₂) : l₁.toFilterDistortion I c₁ ≤ l₂.toFilterDistortion I c₂ := iInf_mono fun _ => iInf_mono' fun hr => ⟨hr.mono h, principal_mono.2 fun _ => MemBaseSet.mono I h hc fun _ _ => le_rfl⟩ -@[mono] +@[gcongr, mono] theorem toFilter_mono (I : Box ι) {l₁ l₂ : IntegrationParams} (h : l₁ ≤ l₂) : l₁.toFilter I ≤ l₂.toFilter I := iSup_mono fun _ => toFilterDistortion_mono I h le_rfl -@[mono] +@[gcongr, mono] theorem toFilteriUnion_mono (I : Box ι) {l₁ l₂ : IntegrationParams} (h : l₁ ≤ l₂) (π₀ : Prepartition I) : l₁.toFilteriUnion I π₀ ≤ l₂.toFilteriUnion I π₀ := iSup_mono fun _ => inf_le_inf_right _ <| toFilterDistortion_mono _ h le_rfl diff --git a/Mathlib/Analysis/BoxIntegral/UnitPartition.lean b/Mathlib/Analysis/BoxIntegral/UnitPartition.lean index 092ae83e8c61f..17d078e1e0df9 100644 --- a/Mathlib/Analysis/BoxIntegral/UnitPartition.lean +++ b/Mathlib/Analysis/BoxIntegral/UnitPartition.lean @@ -3,6 +3,8 @@ Copyright (c) 2024 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ +import Mathlib.Algebra.Module.ZLattice.Basic +import Mathlib.Analysis.BoxIntegral.Integrability import Mathlib.Analysis.BoxIntegral.Partition.Measure import Mathlib.Analysis.BoxIntegral.Partition.Tagged @@ -11,13 +13,12 @@ import Mathlib.Analysis.BoxIntegral.Partition.Tagged Fix `n` a positive integer. `BoxIntegral.unitPartition.box` are boxes in `ι → ℝ` obtained by dividing the unit box uniformly into boxes of side length `1 / n` and translating the boxes by -the lattice `ι → ℤ` so that they cover the whole space. For fixed `n`, there are indexed by vectors `ν : ι → ℤ`. Let `B` be a `BoxIntegral`. A `unitPartition.box` is admissible for `B` (more precisely its index is admissible) if it is contained in `B`. There are finitely many admissible `unitPartition.box` for `B` and thus we can form the corresponing tagged prepartition, see -`BoxIntegral.unitPartition.prepartition` (note that each `unitPartition.Box` comes with its +`BoxIntegral.unitPartition.prepartition` (note that each `unitPartition.box` comes with its tag situated at its "upper most" vertex). If `B` satisfies `hasIntegralVertices`, that is its vertices are in `ι → ℤ`, then the corresponding prepartition is actually a partition. @@ -35,6 +36,20 @@ coordinates in `ℤ` * `BoxIntegral.unitPartition.prepartition_isPartition`: For `B : BoxIntegral.Box`, if `B` has integral vertices, then the prepartition of `unitPartition.box` admissible for `B` is a partition of `B`. + +* `tendsto_tsum_div_pow_atTop_integral`: let `s` be a bounded, measurable set of `ι → ℝ` +whose frontier has zero volume and let `F` be a continuous function. Then the limit as `n → ∞` +of `∑ F x / n ^ card ι`, where the sum is over the points in `s ∩ n⁻¹ • (ι → ℤ)`, tends to the +integral of `F` over `s`. + +* `tendsto_card_div_pow_atTop_volume`: let `s` be a bounded, measurable set of `ι → ℝ` whose +frontier has zero volume. Then the limit as `n → ∞` of `card (s ∩ n⁻¹ • (ι → ℤ)) / n ^ card ι` +tends to the volume of `s`. + +* `tendsto_card_div_pow_atTop_volume'`: a version of `tendsto_card_div_pow_atTop_volume` where we +assume in addition that `x • s ⊆ y • s` whenever `0 < x ≤ y`. Then we get the same limit +`card (s ∩ x⁻¹ • (ι → ℤ)) / x ^ card ι → volume s` but the limit is over a real variable `x`. + -/ noncomputable section @@ -58,13 +73,14 @@ theorem BoxIntegral.le_hasIntegralVertices_of_isBounded [Finite ι] {s : Set (ι let C : ℕ := ⌈R⌉₊ have hC := Nat.ceil_pos.mpr hR₁ let I : Box ι := Box.mk (fun _ ↦ - C) (fun _ ↦ C ) - (fun _ ↦ by simp only [neg_lt_self_iff, Nat.cast_pos, hC]) + (fun _ ↦ by simp [C, neg_lt_self_iff, Nat.cast_pos, hC]) refine ⟨I, ⟨fun _ ↦ - C, fun _ ↦ C, fun i ↦ (Int.cast_neg_natCast C).symm, fun _ ↦ rfl⟩, le_trans hR₂ ?_⟩ suffices Metric.ball (0 : ι → ℝ) C ≤ I from le_trans (Metric.ball_subset_ball (Nat.le_ceil R)) this intro x hx - simp_rw [mem_ball_zero_iff, pi_norm_lt_iff (Nat.cast_pos.mpr hC), Real.norm_eq_abs, abs_lt] at hx + simp_rw [C, mem_ball_zero_iff, pi_norm_lt_iff (Nat.cast_pos.mpr hC), + Real.norm_eq_abs, abs_lt] at hx exact fun i ↦ ⟨(hx i).1, le_of_lt (hx i).2⟩ end hasIntegralVertices @@ -186,7 +202,7 @@ theorem setFinite_index {s : Set (ι → ℝ)} (hs₁ : NullMeasurableSet s) (hs (by simp only [Set.iUnion_subset_iff, Set.inter_subset_right, implies_true]) hs₂ · rw [Set.mem_setOf, Set.inter_eq_self_of_subset_left hν, volume_box] -/-- For `B : BoxIntegral.Box`, the set of indices of `unitPartition.Box` that are subsets of `B`. +/-- For `B : BoxIntegral.Box`, the set of indices of `unitPartition.box` that are subsets of `B`. This is a finite set. These boxes cover `B` if it has integral vertices, see `unitPartition.prepartition_isPartition`. -/ def admissibleIndex (B : Box ι) : Finset (ι → ℤ) := by @@ -293,4 +309,180 @@ theorem prepartition_isPartition {B : Box ι} (hB : hasIntegralVertices B) : rw [TaggedPrepartition.mem_toPrepartition, mem_prepartition_iff] exact ⟨index n x, mem_admissibleIndex_of_mem_box n hB hx, rfl⟩ +open Submodule Pointwise BigOperators + +open scoped Pointwise + +variable (c : ℝ) (s : Set (ι → ℝ)) (F : (ι → ℝ) → ℝ) + +-- The image of `ι → ℤ` inside `ι → ℝ` +local notation "L" => span ℤ (Set.range (Pi.basisFun ℝ ι)) + +variable {n} in +theorem mem_smul_span_iff {v : ι → ℝ} : + v ∈ (n : ℝ)⁻¹ • L ↔ ∀ i, n * v i ∈ Set.range (algebraMap ℤ ℝ) := by + rw [ZSpan.smul _ (inv_ne_zero (NeZero.ne _)), Basis.mem_span_iff_repr_mem] + simp_rw [Basis.repr_isUnitSMul, Pi.basisFun_repr, Units.smul_def, Units.val_inv_eq_inv_val, + IsUnit.unit_spec, inv_inv, smul_eq_mul] + +theorem tag_mem_smul_span (ν : ι → ℤ) : + tag n ν ∈ (n : ℝ)⁻¹ • L := by + refine mem_smul_span_iff.mpr fun i ↦ ⟨ν i + 1, ?_⟩ + rw [tag_apply, div_eq_inv_mul, ← mul_assoc, mul_inv_cancel_of_invertible, one_mul, map_add, + map_one, eq_intCast] + +theorem tag_index_eq_self_of_mem_smul_span {x : ι → ℝ} (hx : x ∈ (n : ℝ)⁻¹ • L) : + tag n (index n x) = x := by + rw [mem_smul_span_iff] at hx + ext i + obtain ⟨a, ha⟩ : ∃ a : ℤ, a = n * x i := hx i + rwa [tag_apply, index_apply, Int.cast_sub, Int.cast_one, sub_add_cancel, ← ha, Int.ceil_intCast, + div_eq_iff (NeZero.ne _), mul_comm] + +theorem eq_of_mem_smul_span_of_index_eq_index {x y : ι → ℝ} (hx : x ∈ (n : ℝ)⁻¹ • L) + (hy : y ∈ (n : ℝ)⁻¹ • L) (h : index n x = index n y) : x = y := by + rw [← tag_index_eq_self_of_mem_smul_span n hx, ← tag_index_eq_self_of_mem_smul_span n hy, h] + +theorem integralSum_eq_tsum_div {B : Box ι} (hB : hasIntegralVertices B) (hs₀ : s ≤ B) : + integralSum (Set.indicator s F) (BoxAdditiveMap.toSMul (Measure.toBoxAdditive volume)) + (prepartition n B) = (∑' x : ↑(s ∩ (n : ℝ)⁻¹ • L), F x) / n ^ card ι := by + classical + unfold integralSum + have : Fintype ↑(s ∩ (n : ℝ)⁻¹ • L) := by + apply Set.Finite.fintype + rw [← coe_pointwise_smul, ZSpan.smul _ (inv_ne_zero (NeZero.ne _))] + exact ZSpan.setFinite_inter _ (B.isBounded.subset hs₀) + rw [tsum_fintype, Finset.sum_set_coe, Finset.sum_div, eq_comm] + simp_rw [Set.indicator_apply, apply_ite, BoxAdditiveMap.toSMul_apply, Measure.toBoxAdditive_apply, + smul_eq_mul, mul_zero, Finset.sum_ite, Finset.sum_const_zero, add_zero] + refine Finset.sum_bij (fun x _ ↦ box n (index n x)) (fun _ hx ↦ Finset.mem_filter.mpr ?_) + (fun _ hx _ hy h ↦ ?_) (fun I hI ↦ ?_) (fun _ hx ↦ ?_) + · rw [Set.mem_toFinset] at hx + refine ⟨mem_prepartition_boxes_iff.mpr + ⟨index n _, mem_admissibleIndex_of_mem_box n hB (hs₀ hx.1), rfl⟩, ?_⟩ + simp_rw [prepartition_tag n (mem_admissibleIndex_of_mem_box n hB (hs₀ hx.1)), + tag_index_eq_self_of_mem_smul_span n hx.2, hx.1] + · rw [Set.mem_toFinset] at hx hy + exact eq_of_mem_smul_span_of_index_eq_index n hx.2 hy.2 (box_injective n h) + · rw [Finset.mem_filter] at hI + refine ⟨(prepartition n B).tag I, Set.mem_toFinset.mpr ⟨hI.2, ?_⟩, box_index_tag_eq_self n hI.1⟩ + rw [← box_index_tag_eq_self n hI.1, prepartition_tag n + (mem_admissibleIndex_of_mem_box n hB (hs₀ hI.2))] + exact tag_mem_smul_span _ _ + · rw [Set.mem_toFinset] at hx + rw [volume_box, prepartition_tag n (mem_admissibleIndex_of_mem_box n hB (hs₀ hx.1)), + tag_index_eq_self_of_mem_smul_span n hx.2, ENNReal.toReal_div, + ENNReal.one_toReal, ENNReal.toReal_pow, ENNReal.toReal_nat, mul_comm_div, one_mul] + +open Filter + +/-- Let `s` be a bounded, measurable set of `ι → ℝ` whose frontier has zero volume and let `F` +be a continuous function. Then the limit as `n → ∞` of `∑ F x / n ^ card ι`, where the sum is +over the points in `s ∩ n⁻¹ • (ι → ℤ)`, tends to the integral of `F` over `s`. -/ +theorem _root_.tendsto_tsum_div_pow_atTop_integral (hF : Continuous F) (hs₁ : IsBounded s) + (hs₂ : MeasurableSet s) (hs₃ : volume (frontier s) = 0) : + Tendsto (fun n : ℕ ↦ (∑' x : ↑(s ∩ (n : ℝ)⁻¹ • L), F x) / n ^ card ι) + atTop (nhds (∫ x in s, F x)) := by + obtain ⟨B, hB, hs₀⟩ := le_hasIntegralVertices_of_isBounded hs₁ + refine Metric.tendsto_atTop.mpr fun ε hε ↦ ?_ + have h₁ : ∃ C, ∀ x ∈ Box.Icc B, ‖Set.indicator s F x‖ ≤ C := by + obtain ⟨C₀, h₀⟩ := (Box.isCompact_Icc B).exists_bound_of_continuousOn hF.continuousOn + refine ⟨max 0 C₀, fun x hx ↦ ?_⟩ + rw [Set.indicator] + split_ifs with hs + · exact le_max_of_le_right (h₀ x hx) + · exact norm_zero.trans_le <|le_max_left 0 _ + have h₂ : ∀ᵐ x, ContinuousAt (s.indicator F) x := by + filter_upwards [compl_mem_ae_iff.mpr hs₃] with _ h + using (hF.continuousOn).continuousAt_indicator h + obtain ⟨r, hr₁, hr₂⟩ := (hasIntegral_iff.mp <| + AEContinuous.hasBoxIntegral (volume : Measure (ι → ℝ)) h₁ h₂ + IntegrationParams.Riemann) (ε / 2) (half_pos hε) + refine ⟨⌈(r 0 0 : ℝ)⁻¹⌉₊, fun n hn ↦ lt_of_le_of_lt ?_ (half_lt_self_iff.mpr hε)⟩ + have : NeZero n := + ⟨Nat.ne_zero_iff_zero_lt.mpr <| (Nat.ceil_pos.mpr (inv_pos.mpr (r 0 0).prop)).trans_le hn⟩ + rw [← integralSum_eq_tsum_div _ s F hB hs₀, ← Measure.restrict_restrict_of_subset hs₀, + ← integral_indicator hs₂] + refine hr₂ 0 _ ⟨?_, fun _ ↦ ?_, fun h ↦ ?_, fun h ↦ ?_⟩ (prepartition_isPartition _ hB) + · rw [show r 0 = fun _ ↦ r 0 0 from funext_iff.mpr (hr₁ 0 rfl)] + apply prepartition_isSubordinate n B + rw [one_div, inv_le_comm₀ (mod_cast (Nat.pos_of_neZero n)) (r 0 0).prop] + exact le_trans (Nat.le_ceil _) (Nat.cast_le.mpr hn) + · exact prepartition_isHenstock n B + · simp only [IntegrationParams.Riemann, Bool.false_eq_true] at h + · simp only [IntegrationParams.Riemann, Bool.false_eq_true] at h + +/-- Let `s` be a bounded, measurable set of `ι → ℝ` whose frontier has zero volume. Then the limit +as `n → ∞` of `card (s ∩ n⁻¹ • (ι → ℤ)) / n ^ card ι` tends to the volume of `s`. This is a +special case of `tendsto_card_div_pow` with `F = 1`. -/ +theorem _root_.tendsto_card_div_pow_atTop_volume (hs₁ : IsBounded s) + (hs₂ : MeasurableSet s) (hs₃ : volume (frontier s) = 0) : + Tendsto (fun n : ℕ ↦ (Nat.card ↑(s ∩ (n : ℝ)⁻¹ • L) : ℝ) / n ^ card ι) + atTop (nhds (volume s).toReal) := by + convert tendsto_tsum_div_pow_atTop_integral s (fun _ ↦ 1) continuous_const hs₁ hs₂ hs₃ + · rw [tsum_const, nsmul_eq_mul, mul_one, Nat.cast_inj] + · rw [setIntegral_const, smul_eq_mul, mul_one] + +private def tendsto_card_div_pow₁ {c : ℝ} (hc : c ≠ 0) : + ↑(s ∩ c⁻¹ • L) ≃ ↑(c • s ∩ L) := + Equiv.subtypeEquiv (Equiv.smulRight hc) (fun x ↦ by + simp_rw [Set.mem_inter_iff, Equiv.smulRight_apply, Set.smul_mem_smul_set_iff₀ hc, + ← Set.mem_inv_smul_set_iff₀ hc]) + +private theorem tendsto_card_div_pow₂ (hs₁ : IsBounded s) + (hs₄ : ∀ ⦃x y : ℝ⦄, 0 < x → x ≤ y → x • s ⊆ y • s) {x y : ℝ} (hx : 0 < x) (hy : x ≤ y) : + Nat.card ↑(s ∩ x⁻¹ • L) ≤ Nat.card ↑(s ∩ y⁻¹ • L) := by + rw [Nat.card_congr (tendsto_card_div_pow₁ s hx.ne'), + Nat.card_congr (tendsto_card_div_pow₁ s (hx.trans_le hy).ne')] + refine Nat.card_mono ?_ ?_ + · exact ZSpan.setFinite_inter _ (IsBounded.smul₀ hs₁ y) + · exact Set.inter_subset_inter_left _ <| hs₄ hx hy + +private theorem tendsto_card_div_pow₃ (hs₁ : IsBounded s) + (hs₄ : ∀ ⦃x y : ℝ⦄, 0 < x → x ≤ y → x • s ⊆ y • s) : + ∀ᶠ x : ℝ in atTop, (Nat.card ↑(s ∩ (⌊x⌋₊ : ℝ)⁻¹ • L) : ℝ) / x ^ card ι ≤ + (Nat.card ↑(s ∩ x⁻¹ • L) : ℝ) / x ^ card ι := by + filter_upwards [eventually_ge_atTop 1] with x hx + gcongr + exact tendsto_card_div_pow₂ s hs₁ hs₄ (Nat.cast_pos.mpr (Nat.floor_pos.mpr hx)) + (Nat.floor_le (zero_le_one.trans hx)) + +private theorem tendsto_card_div_pow₄ (hs₁ : IsBounded s) + (hs₄ : ∀ ⦃x y : ℝ⦄, 0 < x → x ≤ y → x • s ⊆ y • s) : + ∀ᶠ x : ℝ in atTop, (Nat.card ↑(s ∩ x⁻¹ • L) : ℝ) / x ^ card ι ≤ + (Nat.card ↑(s ∩ (⌈x⌉₊ : ℝ)⁻¹ • L) : ℝ) / x ^ card ι := by + filter_upwards [eventually_gt_atTop 0] with x hx + gcongr + exact tendsto_card_div_pow₂ s hs₁ hs₄ hx (Nat.le_ceil _) + +private theorem tendsto_card_div_pow₅ : + (fun x ↦ (Nat.card ↑(s ∩ (⌊x⌋₊ : ℝ)⁻¹ • L) : ℝ) / ⌊x⌋₊ ^ card ι * (⌊x⌋₊ / x) ^ card ι) + =ᶠ[atTop] (fun x ↦ (Nat.card ↑(s ∩ (⌊x⌋₊ : ℝ)⁻¹ • L) : ℝ) / x ^ card ι) := by + filter_upwards [eventually_ge_atTop 1] with x hx + have : 0 < ⌊x⌋₊ := Nat.floor_pos.mpr hx + rw [div_pow, mul_div, div_mul_cancel₀ _ (by positivity)] + +private theorem tendsto_card_div_pow₆ : + (fun x ↦ (Nat.card ↑(s ∩ (⌈x⌉₊ : ℝ)⁻¹ • L) : ℝ) / ⌈x⌉₊ ^ card ι * (⌈x⌉₊ / x) ^ card ι) + =ᶠ[atTop] (fun x ↦ (Nat.card ↑(s ∩ (⌈x⌉₊ : ℝ)⁻¹ • L) : ℝ) / x ^ card ι) := by + filter_upwards [eventually_ge_atTop 1] with x hx + have : 0 < ⌊x⌋₊ := Nat.floor_pos.mpr hx + rw [div_pow, mul_div, div_mul_cancel₀ _ (by positivity)] + +/-- A version of `tendsto_card_div_pow_atTop_volume` for a real variable. -/ +theorem _root_.tendsto_card_div_pow_atTop_volume' (hs₁ : IsBounded s) + (hs₂ : MeasurableSet s) (hs₃ : volume (frontier s) = 0) + (hs₄ : ∀ ⦃x y : ℝ⦄, 0 < x → x ≤ y → x • s ⊆ y • s) : + Tendsto (fun x : ℝ ↦ (Nat.card ↑(s ∩ x⁻¹ • L) : ℝ) / x ^ card ι) + atTop (nhds (volume s).toReal) := by + rw [show (volume s).toReal = (volume s).toReal * 1 ^ card ι by ring] + refine tendsto_of_tendsto_of_tendsto_of_le_of_le' ?_ ?_ + (tendsto_card_div_pow₃ s hs₁ hs₄) (tendsto_card_div_pow₄ s hs₁ hs₄) + · refine Tendsto.congr' (tendsto_card_div_pow₅ s) (Tendsto.mul ?_ (Tendsto.pow ?_ _)) + · exact Tendsto.comp (tendsto_card_div_pow_atTop_volume s hs₁ hs₂ hs₃) tendsto_nat_floor_atTop + · exact tendsto_nat_floor_div_atTop + · refine Tendsto.congr' (tendsto_card_div_pow₆ s) (Tendsto.mul ?_ (Tendsto.pow ?_ _)) + · exact Tendsto.comp (tendsto_card_div_pow_atTop_volume s hs₁ hs₂ hs₃) tendsto_nat_ceil_atTop + · exact tendsto_nat_ceil_div_atTop + end BoxIntegral.unitPartition diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean index 76c6e66606ed2..a05dd23178aaa 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Instances.lean @@ -465,7 +465,7 @@ lemma spectrum_star_mul_self_nonneg {b : A} : ∀ x ∈ spectrum ℝ (star b * b have h_c_spec₀ : SpectrumRestricts (- (star c * c)) (ContinuousMap.realToNNReal ·) := by simp only [SpectrumRestricts.nnreal_iff, h_eq_a_neg] rw [← cfc_pow _ _ (ha := .star_mul_self b)] - simp only [cfc_map_spectrum (R := ℝ) (fun x => (-ContinuousMap.id ℝ ⊔ 0) x ^ 3) (star b * b)] + simp only [a, cfc_map_spectrum (R := ℝ) (fun x => (-ContinuousMap.id ℝ ⊔ 0) x ^ 3) (star b * b)] rintro - ⟨x, -, rfl⟩ simp have c_eq := star_mul_self_add_self_mul_star c diff --git a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean index 6cc0fe177c661..103afe35d71f9 100644 --- a/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean +++ b/Mathlib/Analysis/CStarAlgebra/ContinuousFunctionalCalculus/Order.lean @@ -248,7 +248,7 @@ lemma mem_Icc_algebraMap_iff_nnnorm_le {x : A} {r : ℝ≥0} : lemma mem_Icc_iff_norm_le_one {x : A} : x ∈ Icc 0 1 ↔ 0 ≤ x ∧ ‖x‖ ≤ 1 := by - simpa only [map_one] using mem_Icc_algebraMap_iff_norm_le zero_le_one + simpa only [map_one] using mem_Icc_algebraMap_iff_norm_le zero_le_one (A := A) lemma mem_Icc_iff_nnnorm_le_one {x : A} : x ∈ Icc 0 1 ↔ 0 ≤ x ∧ ‖x‖₊ ≤ 1 := @@ -291,9 +291,10 @@ lemma le_iff_norm_sqrt_mul_rpow {a b : A} (hbu : IsUnit b) (ha : 0 ≤ a) (hb : lift b to Aˣ using hbu have hbab : 0 ≤ (b : A) ^ (-(1 / 2) : ℝ) * a * (b : A) ^ (-(1 / 2) : ℝ) := conjugate_nonneg_of_nonneg ha rpow_nonneg + #adaptation_note /-- 2024-11-10 added `(R := A)` -/ conv_rhs => rw [← sq_le_one_iff₀ (norm_nonneg _), sq, ← CStarRing.norm_star_mul_self, star_mul, - IsSelfAdjoint.of_nonneg sqrt_nonneg, IsSelfAdjoint.of_nonneg rpow_nonneg, + IsSelfAdjoint.of_nonneg (R := A) sqrt_nonneg, IsSelfAdjoint.of_nonneg rpow_nonneg, ← mul_assoc, mul_assoc _ _ (sqrt a), sqrt_mul_sqrt_self a, CStarAlgebra.norm_le_one_iff_of_nonneg _ hbab] refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ diff --git a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean index 2f3e0be74bdfb..70091c5af4b09 100644 --- a/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/BumpFunction/FiniteDimension.lean @@ -93,7 +93,8 @@ theorem IsOpen.exists_smooth_support_eq {s : Set E} (hs : IsOpen s) : rcases exists_smooth_tsupport_subset (hs.mem_nhds hx) with ⟨f, hf⟩ let g : ι := ⟨f, (subset_tsupport f).trans hf.1, hf.2.1, hf.2.2.1, hf.2.2.2.1⟩ have : x ∈ support (g : E → ℝ) := by - simp only [hf.2.2.2.2, Subtype.coe_mk, mem_support, Ne, one_ne_zero, not_false_iff] + simp only [g, hf.2.2.2.2, Subtype.coe_mk, mem_support, Ne, one_ne_zero, + not_false_iff] exact mem_iUnion_of_mem _ this simp_rw [← this] apply isOpen_iUnion_countable diff --git a/Mathlib/Analysis/Calculus/ContDiff/Analytic.lean b/Mathlib/Analysis/Calculus/ContDiff/Analytic.lean deleted file mode 100644 index 8ba3cda66b843..0000000000000 --- a/Mathlib/Analysis/Calculus/ContDiff/Analytic.lean +++ /dev/null @@ -1,55 +0,0 @@ -/- -Copyright (c) 2021 Yury Kudryashov. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Yury Kudryashov --/ -import Mathlib.Analysis.Calculus.ContDiff.Defs -import Mathlib.Analysis.Calculus.FDeriv.Analytic - -/-! -# Analytic functions are `C^∞`. --/ - -open Set ContDiff - -variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] - {E : Type*} [NormedAddCommGroup E] [NormedSpace 𝕜 E] - {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] - {f : E → F} {s : Set E} {x : E} {n : WithTop ℕ∞} - -/-- An analytic function is infinitely differentiable. -/ -protected theorem AnalyticOnNhd.contDiffOn [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) : - ContDiffOn 𝕜 n f s := by - let t := { x | AnalyticAt 𝕜 f x } - suffices ContDiffOn 𝕜 ω f t from (this.of_le le_top).mono h - rw [← contDiffOn_infty_iff_contDiffOn_omega] - have H : AnalyticOnNhd 𝕜 f t := fun _x hx ↦ hx - have t_open : IsOpen t := isOpen_analyticAt 𝕜 f - exact contDiffOn_of_continuousOn_differentiableOn - (fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr - fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) - (fun m _ ↦ (H.iteratedFDeriv m).differentiableOn.congr - fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) - -/-- An analytic function on the whole space is infinitely differentiable there. -/ -theorem AnalyticOnNhd.contDiff [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f univ) : - ContDiff 𝕜 n f := by - rw [← contDiffOn_univ] - exact h.contDiffOn - -theorem AnalyticAt.contDiffAt [CompleteSpace F] (h : AnalyticAt 𝕜 f x) {n : ℕ∞} : - ContDiffAt 𝕜 n f x := by - obtain ⟨s, hs, hf⟩ := h.exists_mem_nhds_analyticOnNhd - exact hf.contDiffOn.contDiffAt hs - -protected lemma AnalyticWithinAt.contDiffWithinAt [CompleteSpace F] {f : E → F} {s : Set E} {x : E} - (h : AnalyticWithinAt 𝕜 f s x) {n : ℕ∞} : ContDiffWithinAt 𝕜 n f s x := by - rcases h.exists_analyticAt with ⟨g, fx, fg, hg⟩ - exact hg.contDiffAt.contDiffWithinAt.congr (fg.mono (subset_insert _ _)) fx - -protected lemma AnalyticOn.contDiffOn [CompleteSpace F] {f : E → F} {s : Set E} - (h : AnalyticOn 𝕜 f s) {n : ℕ∞} : ContDiffOn 𝕜 n f s := - fun x m ↦ (h x m).contDiffWithinAt - -@[deprecated (since := "2024-09-26")] -alias AnalyticWithinOn.contDiffOn := AnalyticOn.contDiffOn diff --git a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean index ad3ed57edf02c..7b0fc7934c102 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Basic.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Basic.lean @@ -70,21 +70,13 @@ theorem iteratedFDeriv_zero_fun {n : ℕ} : (iteratedFDeriv 𝕜 n fun _ : E ↦ funext fun x ↦ by simpa [← iteratedFDerivWithin_univ] using iteratedFDerivWithin_zero_fun uniqueDiffOn_univ (mem_univ x) -theorem contDiff_zero_fun : ContDiff 𝕜 n fun _ : E => (0 : F) := by - suffices ContDiff 𝕜 ω (fun _ : E => (0 : F)) from this.of_le le_top - rw [← contDiff_infty_iff_contDiff_omega] - apply contDiff_of_differentiable_iteratedFDeriv fun m _ ↦ ?_ - rw [iteratedFDeriv_zero_fun] - exact differentiable_const (0 : E[×m]→L[𝕜] F) +theorem contDiff_zero_fun : ContDiff 𝕜 n fun _ : E => (0 : F) := + analyticOnNhd_const.contDiff /-- Constants are `C^∞`. -/ -theorem contDiff_const {c : F} : ContDiff 𝕜 n fun _ : E => c := by - suffices h : ContDiff 𝕜 ω fun _ : E => c from h.of_le le_top - rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] - refine ⟨differentiable_const c, ?_⟩ - rw [fderiv_const] - exact contDiff_zero_fun +theorem contDiff_const {c : F} : ContDiff 𝕜 n fun _ : E => c := + analyticOnNhd_const.contDiff theorem contDiffOn_const {c : F} {s : Set E} : ContDiffOn 𝕜 n (fun _ : E => c) s := contDiff_const.contDiffOn @@ -141,14 +133,10 @@ theorem contDiffWithinAt_singleton : ContDiffWithinAt 𝕜 n f {x} x := /-! ### Smoothness of linear functions -/ -/-- Unbundled bounded linear functions are `C^∞`. +/-- Unbundled bounded linear functions are `C^n`. -/ -theorem IsBoundedLinearMap.contDiff (hf : IsBoundedLinearMap 𝕜 f) : ContDiff 𝕜 n f := by - suffices h : ContDiff 𝕜 ω f from h.of_le le_top - rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] - refine ⟨hf.differentiable, ?_⟩ - simp_rw [hf.fderiv] - exact contDiff_const +theorem IsBoundedLinearMap.contDiff (hf : IsBoundedLinearMap 𝕜 f) : ContDiff 𝕜 n f := + (ContinuousLinearMap.analyticOnNhd hf.toContinuousLinearMap univ).contDiff theorem ContinuousLinearMap.contDiff (f : E →L[𝕜] F) : ContDiff 𝕜 n f := f.isBoundedLinearMap.contDiff @@ -162,7 +150,7 @@ theorem LinearIsometry.contDiff (f : E →ₗᵢ[𝕜] F) : ContDiff 𝕜 n f := theorem LinearIsometryEquiv.contDiff (f : E ≃ₗᵢ[𝕜] F) : ContDiff 𝕜 n f := (f : E →L[𝕜] F).contDiff -/-- The identity is `C^∞`. +/-- The identity is `C^n`. -/ theorem contDiff_id : ContDiff 𝕜 n (id : E → E) := IsBoundedLinearMap.id.contDiff @@ -176,14 +164,10 @@ theorem contDiffAt_id {x} : ContDiffAt 𝕜 n (id : E → E) x := theorem contDiffOn_id {s} : ContDiffOn 𝕜 n (id : E → E) s := contDiff_id.contDiffOn -/-- Bilinear functions are `C^∞`. +/-- Bilinear functions are `C^n`. -/ -theorem IsBoundedBilinearMap.contDiff (hb : IsBoundedBilinearMap 𝕜 b) : ContDiff 𝕜 n b := by - suffices h : ContDiff 𝕜 ω b from h.of_le le_top - rw [← contDiff_infty_iff_contDiff_omega, contDiff_top_iff_fderiv] - refine ⟨hb.differentiable, ?_⟩ - simp only [hb.fderiv] - exact hb.isBoundedLinearMap_deriv.contDiff +theorem IsBoundedBilinearMap.contDiff (hb : IsBoundedBilinearMap 𝕜 b) : ContDiff 𝕜 n b := + (hb.toContinuousLinearMap.analyticOnNhd_bilinear _).contDiff /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `g ∘ f` admits a Taylor series whose `k`-th term is given by `g ∘ (p k)`. -/ @@ -199,9 +183,20 @@ theorem HasFTaylorSeriesUpToOn.continuousLinearMap_comp {n : WithTop ℕ∞} (g /-- Composition by continuous linear maps on the left preserves `C^n` functions in a domain at a point. -/ theorem ContDiffWithinAt.continuousLinearMap_comp (g : F →L[𝕜] G) - (hf : ContDiffWithinAt 𝕜 n f s x) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := fun m hm ↦ by - rcases hf m hm with ⟨u, hu, p, hp⟩ - exact ⟨u, hu, _, hp.continuousLinearMap_comp g⟩ + (hf : ContDiffWithinAt 𝕜 n f s x) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := by + match n with + | ω => + obtain ⟨u, hu, p, hp, h'p⟩ := hf + refine ⟨u, hu, _, hp.continuousLinearMap_comp g, fun i ↦ ?_⟩ + change AnalyticOn 𝕜 + (fun x ↦ (ContinuousLinearMap.compContinuousMultilinearMapL 𝕜 + (fun _ : Fin i ↦ E) F G g) (p x i)) u + apply AnalyticOnNhd.comp_analyticOn _ (h'p i) (Set.mapsTo_univ _ _) + exact ContinuousLinearMap.analyticOnNhd _ _ + | (n : ℕ∞) => + intro m hm + rcases hf m hm with ⟨u, hu, p, hp⟩ + exact ⟨u, hu, _, hp.continuousLinearMap_comp g⟩ /-- Composition by continuous linear maps on the left preserves `C^n` functions in a domain at a point. -/ @@ -224,8 +219,8 @@ theorem ContinuousLinearMap.iteratedFDerivWithin_comp_left {f : E → F} (g : F (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) {i : ℕ} (hi : i ≤ n) : iteratedFDerivWithin 𝕜 i (g ∘ f) s x = g.compContinuousMultilinearMap (iteratedFDerivWithin 𝕜 i f s x) := - (((hf.ftaylorSeriesWithin hs).continuousLinearMap_comp g).eq_iteratedFDerivWithin_of_uniqueDiffOn - (mod_cast hi) hs hx).symm + ((((hf.of_le hi).ftaylorSeriesWithin hs).continuousLinearMap_comp + g).eq_iteratedFDerivWithin_of_uniqueDiffOn le_rfl hs hx).symm /-- The iterated derivative of the composition with a linear map on the left is obtained by applying the linear map to the iterated derivative. -/ @@ -326,7 +321,7 @@ theorem ContinuousLinearEquiv.comp_contDiff_iff (e : F ≃L[𝕜] G) : /-- If `f` admits a Taylor series `p` in a set `s`, and `g` is linear, then `f ∘ g` admits a Taylor series in `g ⁻¹' s`, whose `k`-th term is given by `p k (g v₁, ..., g vₖ)` . -/ -theorem HasFTaylorSeriesUpToOn.compContinuousLinearMap {n : WithTop ℕ∞} +theorem HasFTaylorSeriesUpToOn.compContinuousLinearMap (hf : HasFTaylorSeriesUpToOn n f p s) (g : G →L[𝕜] E) : HasFTaylorSeriesUpToOn n (f ∘ g) (fun x k => (p (g x) k).compContinuousLinearMap fun _ => g) (g ⁻¹' s) := by @@ -353,11 +348,24 @@ theorem HasFTaylorSeriesUpToOn.compContinuousLinearMap {n : WithTop ℕ∞} a domain. -/ theorem ContDiffWithinAt.comp_continuousLinearMap {x : G} (g : G →L[𝕜] E) (hf : ContDiffWithinAt 𝕜 n f s (g x)) : ContDiffWithinAt 𝕜 n (f ∘ g) (g ⁻¹' s) x := by - intro m hm - rcases hf m hm with ⟨u, hu, p, hp⟩ - refine ⟨g ⁻¹' u, ?_, _, hp.compContinuousLinearMap g⟩ - refine g.continuous.continuousWithinAt.tendsto_nhdsWithin ?_ hu - exact (mapsTo_singleton.2 <| mem_singleton _).union_union (mapsTo_preimage _ _) + match n with + | ω => + obtain ⟨u, hu, p, hp, h'p⟩ := hf + refine ⟨g ⁻¹' u, ?_, _, hp.compContinuousLinearMap g, ?_⟩ + · refine g.continuous.continuousWithinAt.tendsto_nhdsWithin ?_ hu + exact (mapsTo_singleton.2 <| mem_singleton _).union_union (mapsTo_preimage _ _) + · intro i + change AnalyticOn 𝕜 (fun x ↦ + ContinuousMultilinearMap.compContinuousLinearMapL (fun _ ↦ g) (p (g x) i)) (⇑g ⁻¹' u) + apply AnalyticOn.comp _ _ (Set.mapsTo_univ _ _) + · exact ContinuousLinearEquiv.analyticOn _ _ + · exact (h'p i).comp (g.analyticOn _) (mapsTo_preimage _ _) + | (n : ℕ∞) => + intro m hm + rcases hf m hm with ⟨u, hu, p, hp⟩ + refine ⟨g ⁻¹' u, ?_, _, hp.compContinuousLinearMap g⟩ + refine g.continuous.continuousWithinAt.tendsto_nhdsWithin ?_ hu + exact (mapsTo_singleton.2 <| mem_singleton _).union_union (mapsTo_preimage _ _) /-- Composition by continuous linear maps on the right preserves `C^n` functions on domains. -/ theorem ContDiffOn.comp_continuousLinearMap (hf : ContDiffOn 𝕜 n f s) (g : G →L[𝕜] E) : @@ -375,8 +383,8 @@ theorem ContinuousLinearMap.iteratedFDerivWithin_comp_right {f : E → F} (g : G (hx : g x ∈ s) {i : ℕ} (hi : i ≤ n) : iteratedFDerivWithin 𝕜 i (f ∘ g) (g ⁻¹' s) x = (iteratedFDerivWithin 𝕜 i f s (g x)).compContinuousLinearMap fun _ => g := - (((hf.ftaylorSeriesWithin hs).compContinuousLinearMap g).eq_iteratedFDerivWithin_of_uniqueDiffOn - (mod_cast hi) h's hx).symm + ((((hf.of_le hi).ftaylorSeriesWithin hs).compContinuousLinearMap + g).eq_iteratedFDerivWithin_of_uniqueDiffOn le_rfl h's hx).symm /-- The iterated derivative within a set of the composition with a linear equiv on the right is obtained by composing the iterated derivative with the linear equiv. -/ @@ -479,12 +487,24 @@ theorem HasFTaylorSeriesUpToOn.prod {n : WithTop ℕ∞} /-- The cartesian product of `C^n` functions at a point in a domain is `C^n`. -/ theorem ContDiffWithinAt.prod {s : Set E} {f : E → F} {g : E → G} (hf : ContDiffWithinAt 𝕜 n f s x) (hg : ContDiffWithinAt 𝕜 n g s x) : ContDiffWithinAt 𝕜 n (fun x : E => (f x, g x)) s x := by - intro m hm - rcases hf m hm with ⟨u, hu, p, hp⟩ - rcases hg m hm with ⟨v, hv, q, hq⟩ - exact - ⟨u ∩ v, Filter.inter_mem hu hv, _, - (hp.mono inter_subset_left).prod (hq.mono inter_subset_right)⟩ + match n with + | ω => + obtain ⟨u, hu, p, hp, h'p⟩ := hf + obtain ⟨v, hv, q, hq, h'q⟩ := hg + refine ⟨u ∩ v, Filter.inter_mem hu hv, _, + (hp.mono inter_subset_left).prod (hq.mono inter_subset_right), fun i ↦ ?_⟩ + change AnalyticOn 𝕜 (fun x ↦ ContinuousMultilinearMap.prodL _ _ _ _ (p x i, q x i)) + (u ∩ v) + apply AnalyticOnNhd.comp_analyticOn (LinearIsometryEquiv.analyticOnNhd _ _) _ + (Set.mapsTo_univ _ _) + exact ((h'p i).mono inter_subset_left).prod ((h'q i).mono inter_subset_right) + | (n : ℕ∞) => + intro m hm + rcases hf m hm with ⟨u, hu, p, hp⟩ + rcases hg m hm with ⟨v, hv, q, hq⟩ + exact + ⟨u ∩ v, Filter.inter_mem hu hv, _, + (hp.mono inter_subset_left).prod (hq.mono inter_subset_right)⟩ /-- The cartesian product of `C^n` functions on domains is `C^n`. -/ theorem ContDiffOn.prod {s : Set E} {f : E → F} {g : E → G} (hf : ContDiffOn 𝕜 n f s) @@ -514,6 +534,7 @@ multiplication is the application of a bilinear map (which is `C^∞`, and there `x ↦ (Dg(f x), Df x)`. As the composition of two `C^n` maps, it is again `C^n`, and we are done. There are two difficulties in this proof. + The first one is that it is an induction over all Banach spaces. In Lean, this is only possible if they belong to a fixed universe. One could formalize this by first proving the statement in this case, and then extending the result to general universes @@ -522,6 +543,7 @@ by embedding all the spaces we consider in a common universe through `ULift`. The second one is that it does not work cleanly for analytic maps: for this case, we need to exhibit a whole sequence of derivatives which are all analytic, not just finitely many of them, so an induction is never enough at a finite step. + Both these difficulties can be overcome with some cost. However, we choose a different path: we write down an explicit formula for the `n`-th derivative of `g ∘ f` in terms of derivatives of `g` and `f` (this is the formula of Faa-Di Bruno) and use this formula to get a suitable Taylor @@ -534,19 +556,44 @@ essentially trivial. theorem ContDiffWithinAt.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F} (x : E) (hg : ContDiffWithinAt 𝕜 n g t (f x)) (hf : ContDiffWithinAt 𝕜 n f s x) (st : MapsTo f s t) : ContDiffWithinAt 𝕜 n (g ∘ f) s x := by - intro m hm - rcases hf m hm with ⟨u, hu, p, hp⟩ - rcases hg m hm with ⟨v, hv, q, hq⟩ - let w := insert x s ∩ (u ∩ f ⁻¹' v) - have wv : w ⊆ f ⁻¹' v := inter_subset_right.trans inter_subset_right - have wu : w ⊆ u := inter_subset_right.trans inter_subset_left - refine ⟨w, ?_, fun y ↦ (q (f y)).taylorComp (p y), hq.comp (hp.mono wu) wv⟩ - apply inter_mem self_mem_nhdsWithin (inter_mem hu ?_) - apply (continuousWithinAt_insert_self.2 hf.continuousWithinAt).preimage_mem_nhdsWithin' - apply nhdsWithin_mono _ _ hv - simp only [image_insert_eq] - apply insert_subset_insert - exact image_subset_iff.mpr st + match n with + | ω => + have h'f : ContDiffWithinAt 𝕜 ω f s x := hf + obtain ⟨u, hu, p, hp, h'p⟩ := h'f + obtain ⟨v, hv, q, hq, h'q⟩ := hg + let w := insert x s ∩ (u ∩ f ⁻¹' v) + have wv : w ⊆ f ⁻¹' v := fun y hy => hy.2.2 + have wu : w ⊆ u := fun y hy => hy.2.1 + refine ⟨w, ?_, fun y ↦ (q (f y)).taylorComp (p y), hq.comp (hp.mono wu) wv, ?_⟩ + · apply inter_mem self_mem_nhdsWithin (inter_mem hu ?_) + apply (continuousWithinAt_insert_self.2 hf.continuousWithinAt).preimage_mem_nhdsWithin' + apply nhdsWithin_mono _ _ hv + simp only [image_insert_eq] + apply insert_subset_insert + exact image_subset_iff.mpr st + · have : AnalyticOn 𝕜 f w := by + have : AnalyticOn 𝕜 (fun y ↦ (continuousMultilinearCurryFin0 𝕜 E F).symm (f y)) w := + ((h'p 0).mono wu).congr fun y hy ↦ (hp.zero_eq' (wu hy)).symm + have : AnalyticOn 𝕜 (fun y ↦ (continuousMultilinearCurryFin0 𝕜 E F) + ((continuousMultilinearCurryFin0 𝕜 E F).symm (f y))) w := + AnalyticOnNhd.comp_analyticOn (LinearIsometryEquiv.analyticOnNhd _ _ ) this + (mapsTo_univ _ _) + simpa using this + exact analyticOn_taylorComp h'q (fun n ↦ (h'p n).mono wu) this wv + | (n : ℕ∞) => + intro m hm + rcases hf m hm with ⟨u, hu, p, hp⟩ + rcases hg m hm with ⟨v, hv, q, hq⟩ + let w := insert x s ∩ (u ∩ f ⁻¹' v) + have wv : w ⊆ f ⁻¹' v := fun y hy => hy.2.2 + have wu : w ⊆ u := fun y hy => hy.2.1 + refine ⟨w, ?_, fun y ↦ (q (f y)).taylorComp (p y), hq.comp (hp.mono wu) wv⟩ + apply inter_mem self_mem_nhdsWithin (inter_mem hu ?_) + apply (continuousWithinAt_insert_self.2 hf.continuousWithinAt).preimage_mem_nhdsWithin' + apply nhdsWithin_mono _ _ hv + simp only [image_insert_eq] + apply insert_subset_insert + exact image_subset_iff.mpr st /-- The composition of `C^n` functions on domains is `C^n`. -/ theorem ContDiffOn.comp {s : Set E} {t : Set F} {g : F → G} {f : E → F} (hg : ContDiffOn 𝕜 n g t) @@ -889,7 +936,7 @@ theorem iteratedFDerivWithin_clm_apply_const_apply induction i generalizing x with | zero => simp | succ i ih => - replace hi : i < n := lt_of_lt_of_le (by norm_cast; simp) hi + replace hi : (i : WithTop ℕ∞) < n := lt_of_lt_of_le (by norm_cast; simp) hi have h_deriv_apply : DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 i (fun y ↦ (c y) u) s) s := (hc.clm_apply contDiffOn_const).differentiableOn_iteratedFDerivWithin hi hs have h_deriv : DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 i c s) s := @@ -919,21 +966,21 @@ Warning: if you think you need this lemma, it is likely that you can simplify yo reformulating the lemma that you're applying next using the tips in Note [continuity lemma statement] -/ -theorem contDiff_prodAssoc : ContDiff 𝕜 ⊤ <| Equiv.prodAssoc E F G := +theorem contDiff_prodAssoc : ContDiff 𝕜 ω <| Equiv.prodAssoc E F G := (LinearIsometryEquiv.prodAssoc 𝕜 E F G).contDiff /-- The natural equivalence `E × (F × G) ≃ (E × F) × G` is smooth. Warning: see remarks attached to `contDiff_prodAssoc` -/ -theorem contDiff_prodAssoc_symm : ContDiff 𝕜 ⊤ <| (Equiv.prodAssoc E F G).symm := +theorem contDiff_prodAssoc_symm : ContDiff 𝕜 ω <| (Equiv.prodAssoc E F G).symm := (LinearIsometryEquiv.prodAssoc 𝕜 E F G).symm.contDiff /-! ### Bundled derivatives are smooth -/ -/-- One direction of `contDiffWithinAt_succ_iff_hasFDerivWithinAt`, but where all derivatives -taken within the same set. Version for partial derivatives / functions with parameters. `f x` is a -`C^n+1` family of functions and `g x` is a `C^n` family of points, then the derivative of `f x` at +/-- One direction of `contDiffWithinAt_succ_iff_hasFDerivWithinAt`, but where all derivatives are +taken within the same set. Version for partial derivatives / functions with parameters. If `f x` is +a `C^n+1` family of functions and `g x` is a `C^n` family of points, then the derivative of `f x` at `g x` depends in a `C^n` way on `x`. We give a general version of this fact relative to sets which may not have unique derivatives, in the following form. If `f : E × F → G` is `C^n+1` at `(x₀, g(x₀))` in `(s ∪ {x₀}) × t ⊆ E × F` and `g : E → F` is `C^n` at `x₀` within some set `s ⊆ E`, @@ -942,7 +989,7 @@ sufficiently close to `x₀` within `s ∪ {x₀}` the function `y ↦ f x y` ha within `t ⊆ F`. For convenience, we return an explicit set of `x`'s where this holds that is a subset of `s ∪ {x₀}`. We need one additional condition, namely that `t` is a neighborhood of `g(x₀)` within `g '' s`. -/ -theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F} {t : Set F} {n : ℕ} +theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F} {t : Set F} (hn : n ≠ ∞) {x₀ : E} (hf : ContDiffWithinAt 𝕜 (n + 1) (uncurry f) (insert x₀ s ×ˢ t) (x₀, g x₀)) (hg : ContDiffWithinAt 𝕜 n g s x₀) (hgt : t ∈ 𝓝[g '' s] g x₀) : ∃ v ∈ 𝓝[insert x₀ s] x₀, v ⊆ insert x₀ s ∧ ∃ f' : E → F →L[𝕜] G, @@ -952,7 +999,8 @@ theorem ContDiffWithinAt.hasFDerivWithinAt_nhds {f : E → F → G} {g : E → F refine nhdsWithin_mono _ ?_ (nhdsWithin_prod self_mem_nhdsWithin hgt) simp_rw [image_subset_iff, mk_preimage_prod, preimage_id', subset_inter_iff, subset_insert, true_and, subset_preimage_image] - obtain ⟨v, hv, hvs, f', hvf', hf'⟩ := contDiffWithinAt_succ_iff_hasFDerivWithinAt'.mp hf + obtain ⟨v, hv, hvs, f_an, f', hvf', hf'⟩ := + (contDiffWithinAt_succ_iff_hasFDerivWithinAt' hn).mp hf refine ⟨(fun z => (z, g z)) ⁻¹' v ∩ insert x₀ s, ?_, inter_subset_right, fun z => (f' (z, g z)).comp (ContinuousLinearMap.inr 𝕜 E F), ?_, ?_⟩ @@ -983,21 +1031,24 @@ theorem ContDiffWithinAt.fderivWithin'' {f : E → F → G} {g : E → F} {t : S (ht : ∀ᶠ x in 𝓝[insert x₀ s] x₀, UniqueDiffWithinAt 𝕜 t (g x)) (hmn : m + 1 ≤ n) (hgt : t ∈ 𝓝[g '' s] g x₀) : ContDiffWithinAt 𝕜 m (fun x => fderivWithin 𝕜 (f x) t (g x)) s x₀ := by - have : ∀ k : ℕ, (k : ℕ∞) ≤ m → - ContDiffWithinAt 𝕜 k (fun x => fderivWithin 𝕜 (f x) t (g x)) s x₀ := fun k hkm ↦ by + have : ∀ k : ℕ, k ≤ m → ContDiffWithinAt 𝕜 k (fun x => fderivWithin 𝕜 (f x) t (g x)) s x₀ := by + intro k hkm obtain ⟨v, hv, -, f', hvf', hf'⟩ := - (hf.of_le <| (add_le_add_right hkm 1).trans hmn).hasFDerivWithinAt_nhds (hg.of_le hkm) hgt + (hf.of_le <| (add_le_add_right hkm 1).trans hmn).hasFDerivWithinAt_nhds (by simp) + (hg.of_le hkm) hgt refine hf'.congr_of_eventuallyEq_insert ?_ filter_upwards [hv, ht] exact fun y hy h2y => (hvf' y hy).fderivWithin h2y match m with | ω => - intro k hk - apply this k hk - exact le_rfl + obtain rfl : n = ω := by simpa using hmn + obtain ⟨v, hv, -, f', hvf', hf'⟩ := hf.hasFDerivWithinAt_nhds (by simp) hg hgt + refine hf'.congr_of_eventuallyEq_insert ?_ + filter_upwards [hv, ht] + exact fun y hy h2y => (hvf' y hy).fderivWithin h2y | ∞ => - rw [contDiffWithinAt_top] - exact fun m => this m (mod_cast le_top) + rw [contDiffWithinAt_infty] + exact fun k ↦ this k (by exact_mod_cast le_top) | (m : ℕ) => exact this _ le_rfl /-- A special case of `ContDiffWithinAt.fderivWithin''` where we require that `s ⊆ g⁻¹(t)`. -/ @@ -1038,7 +1089,7 @@ theorem ContDiffWithinAt.fderivWithin_right (hf : ContDiffWithinAt 𝕜 n f s x /-- `x ↦ fderivWithin 𝕜 f s x (k x)` is smooth at `x₀` within `s`. -/ theorem ContDiffWithinAt.fderivWithin_right_apply - {f : F → G} {k : F → F} {s : Set F} {n : ℕ∞} {x₀ : F} + {f : F → G} {k : F → F} {s : Set F} {x₀ : F} (hf : ContDiffWithinAt 𝕜 n f s x₀) (hk : ContDiffWithinAt 𝕜 m k s x₀) (hs : UniqueDiffOn 𝕜 s) (hmn : m + 1 ≤ n) (hx₀s : x₀ ∈ s) : ContDiffWithinAt 𝕜 m (fun x => fderivWithin 𝕜 f s x (k x)) s x₀ := @@ -1141,7 +1192,6 @@ theorem hasFTaylorSeriesUpToOn_pi {n : WithTop ℕ∞} : (fun x m => ContinuousMultilinearMap.pi fun i => p' i x m) s ↔ ∀ i, HasFTaylorSeriesUpToOn n (φ i) (p' i) s := by set pr := @ContinuousLinearMap.proj 𝕜 _ ι F' _ _ _ - letI : ∀ (m : ℕ) (i : ι), NormedSpace 𝕜 (E[×m]→L[𝕜] F' i) := fun m i => inferInstance set L : ∀ m : ℕ, (∀ i, E[×m]→L[𝕜] F' i) ≃ₗᵢ[𝕜] E[×m]→L[𝕜] ∀ i, F' i := fun m => ContinuousMultilinearMap.piₗᵢ _ _ refine ⟨fun h i => ?_, fun h => ⟨fun x hx => ?_, ?_, ?_⟩⟩ @@ -1165,10 +1215,22 @@ theorem hasFTaylorSeriesUpToOn_pi' {n : WithTop ℕ∞} : theorem contDiffWithinAt_pi : ContDiffWithinAt 𝕜 n Φ s x ↔ ∀ i, ContDiffWithinAt 𝕜 n (fun x => Φ x i) s x := by set pr := @ContinuousLinearMap.proj 𝕜 _ ι F' _ _ _ - refine ⟨fun h i => h.continuousLinearMap_comp (pr i), fun h m hm => ?_⟩ - choose u hux p hp using fun i => h i m hm - exact ⟨⋂ i, u i, Filter.iInter_mem.2 hux, _, - hasFTaylorSeriesUpToOn_pi.2 fun i => (hp i).mono <| iInter_subset _ _⟩ + refine ⟨fun h i => h.continuousLinearMap_comp (pr i), fun h ↦ ?_⟩ + match n with + | ω => + choose u hux p hp h'p using h + refine ⟨⋂ i, u i, Filter.iInter_mem.2 hux, _, + hasFTaylorSeriesUpToOn_pi.2 fun i => (hp i).mono <| iInter_subset _ _, fun m ↦ ?_⟩ + set L : (∀ i, E[×m]→L[𝕜] F' i) ≃ₗᵢ[𝕜] E[×m]→L[𝕜] ∀ i, F' i := + ContinuousMultilinearMap.piₗᵢ _ _ + change AnalyticOn 𝕜 (fun x ↦ L (fun i ↦ p i x m)) (⋂ i, u i) + apply (L.analyticOnNhd univ).comp_analyticOn ?_ (mapsTo_univ _ _) + exact AnalyticOn.pi (fun i ↦ (h'p i m).mono (iInter_subset _ _)) + | (n : ℕ∞) => + intro m hm + choose u hux p hp using fun i => h i m hm + exact ⟨⋂ i, u i, Filter.iInter_mem.2 hux, _, + hasFTaylorSeriesUpToOn_pi.2 fun i => (hp i).mono <| iInter_subset _ _⟩ theorem contDiffOn_pi : ContDiffOn 𝕜 n Φ s ↔ ∀ i, ContDiffOn 𝕜 n (fun x => Φ x i) s := ⟨fun h _ x hx => contDiffWithinAt_pi.1 (h x hx) _, fun h x hx => @@ -1627,7 +1689,9 @@ theorem contDiff_prod_mk_right (e₀ : E) : ContDiff 𝕜 n fun f : F => (e₀, end prodMap -/-! ### Inversion in a complete normed algebra -/ +/-! +### Inversion in a complete normed algebra (or more generally with summable geometric series) +-/ section AlgebraInverse @@ -1637,36 +1701,14 @@ variable {R : Type*} [NormedRing R] [NormedAlgebra 𝕜 R] open NormedRing ContinuousLinearMap Ring /-- In a complete normed algebra, the operation of inversion is `C^n`, for all `n`, at each -invertible element. The proof is by induction, bootstrapping using an identity expressing the -derivative of inversion as a bilinear map of inversion itself. -/ -theorem contDiffAt_ring_inverse [CompleteSpace R] (x : Rˣ) : +invertible element, as it is analytic. -/ +theorem contDiffAt_ring_inverse [HasSummableGeomSeries R] (x : Rˣ) : ContDiffAt 𝕜 n Ring.inverse (x : R) := by - suffices H : ∀ (n : ℕ∞), ContDiffAt 𝕜 n Ring.inverse (x : R) by - intro k hk - exact H ⊤ k (mod_cast le_top) - intro n - induction' n using ENat.nat_induction with n IH Itop - · intro m hm - refine ⟨{ y : R | IsUnit y }, ?_, ?_⟩ - · simpa [nhdsWithin_univ] using x.nhds - · use ftaylorSeriesWithin 𝕜 inverse univ - have : (m : WithTop ℕ∞) = 0 := by exact_mod_cast le_antisymm hm bot_le - rw [this, hasFTaylorSeriesUpToOn_zero_iff] - constructor - · rintro _ ⟨x', rfl⟩ - exact (inverse_continuousAt x').continuousWithinAt - · simp [ftaylorSeriesWithin] - · rw [show ((n.succ : ℕ∞) : WithTop ℕ∞) = n + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] - refine ⟨fun x : R => -mulLeftRight 𝕜 R (inverse x) (inverse x), ?_, ?_⟩ - · refine ⟨{ y : R | IsUnit y }, x.nhds, ?_⟩ - rintro _ ⟨y, rfl⟩ - simp_rw [inverse_unit] - exact hasFDerivAt_ring_inverse y - · convert (mulLeftRight_isBoundedBilinear 𝕜 R).contDiff.neg.comp_contDiffAt (x : R) - (IH.prod IH) - · exact contDiffAt_top.mpr Itop - -variable {𝕜' : Type*} [NormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] [CompleteSpace 𝕜'] + have := AnalyticOnNhd.contDiffOn (analyticOnNhd_inverse (𝕜 := 𝕜) (A := R)) (n := n) + Units.isOpen.uniqueDiffOn x x.isUnit + exact this.contDiffAt (Units.isOpen.mem_nhds x.isUnit) + +variable {𝕜' : Type*} [NormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] theorem contDiffAt_inv {x : 𝕜'} (hx : x ≠ 0) {n} : ContDiffAt 𝕜 n Inv.inv x := by simpa only [Ring.inverse_eq_inv'] using contDiffAt_ring_inverse 𝕜 (Units.mk0 x hx) @@ -1676,10 +1718,7 @@ theorem contDiffOn_inv {n} : ContDiffOn 𝕜 n (Inv.inv : 𝕜' → 𝕜') {0} variable {𝕜} --- TODO: the next few lemmas don't need `𝕜` or `𝕜'` to be complete --- A good way to show this is to generalize `contDiffAt_ring_inverse` to the setting --- of a function `f` such that `∀ᶠ x in 𝓝 a, x * f x = 1`. -theorem ContDiffWithinAt.inv {f : E → 𝕜'} (hf : ContDiffWithinAt 𝕜 n f s x) (hx : f x ≠ 0) : +theorem ContDiffWithinAt.inv {f : E → 𝕜'} {n} (hf : ContDiffWithinAt 𝕜 n f s x) (hx : f x ≠ 0) : ContDiffWithinAt 𝕜 n (fun x => (f x)⁻¹) s x := (contDiffAt_inv 𝕜 hx).comp_contDiffWithinAt x hf @@ -1695,20 +1734,20 @@ theorem ContDiff.inv {f : E → 𝕜'} (hf : ContDiff 𝕜 n f) (h : ∀ x, f x rw [contDiff_iff_contDiffAt]; exact fun x => hf.contDiffAt.inv (h x) -- TODO: generalize to `f g : E → 𝕜'` -theorem ContDiffWithinAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffWithinAt 𝕜 n f s x) +theorem ContDiffWithinAt.div {f g : E → 𝕜} {n} (hf : ContDiffWithinAt 𝕜 n f s x) (hg : ContDiffWithinAt 𝕜 n g s x) (hx : g x ≠ 0) : ContDiffWithinAt 𝕜 n (fun x => f x / g x) s x := by simpa only [div_eq_mul_inv] using hf.mul (hg.inv hx) -theorem ContDiffOn.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffOn 𝕜 n f s) +theorem ContDiffOn.div {f g : E → 𝕜} {n} (hf : ContDiffOn 𝕜 n f s) (hg : ContDiffOn 𝕜 n g s) (h₀ : ∀ x ∈ s, g x ≠ 0) : ContDiffOn 𝕜 n (f / g) s := fun x hx => (hf x hx).div (hg x hx) (h₀ x hx) -nonrec theorem ContDiffAt.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiffAt 𝕜 n f x) +nonrec theorem ContDiffAt.div {f g : E → 𝕜} {n} (hf : ContDiffAt 𝕜 n f x) (hg : ContDiffAt 𝕜 n g x) (hx : g x ≠ 0) : ContDiffAt 𝕜 n (fun x => f x / g x) x := hf.div hg hx -theorem ContDiff.div [CompleteSpace 𝕜] {f g : E → 𝕜} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) +theorem ContDiff.div {f g : E → 𝕜} {n} (hf : ContDiff 𝕜 n f) (hg : ContDiff 𝕜 n g) (h0 : ∀ x, g x ≠ 0) : ContDiff 𝕜 n fun x => f x / g x := by simp only [contDiff_iff_contDiffAt] at * exact fun x => (hf x).div (hg x) (h0 x) @@ -1746,53 +1785,6 @@ section FunctionInverse open ContinuousLinearMap -private theorem PartialHomeomorph.contDiffAt_symm_aux {n : ℕ∞} - [CompleteSpace E] (f : PartialHomeomorph E F) - {f₀' : E ≃L[𝕜] F} {a : F} (ha : a ∈ f.target) - (hf₀' : HasFDerivAt f (f₀' : E →L[𝕜] F) (f.symm a)) (hf : ContDiffAt 𝕜 n f (f.symm a)) : - ContDiffAt 𝕜 n f.symm a := by - -- We prove this by induction on `n` - induction' n using ENat.nat_induction with n IH Itop - · apply contDiffAt_zero.2 - exact ⟨f.target, IsOpen.mem_nhds f.open_target ha, f.continuousOn_invFun⟩ - · obtain ⟨f', ⟨u, hu, hff'⟩, hf'⟩ := contDiffAt_succ_iff_hasFDerivAt.mp hf - rw [show ((n.succ : ℕ∞) : WithTop ℕ∞) = n + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] - -- For showing `n.succ` times continuous differentiability (the main inductive step), it - -- suffices to produce the derivative and show that it is `n` times continuously differentiable - have eq_f₀' : f' (f.symm a) = f₀' := (hff' (f.symm a) (mem_of_mem_nhds hu)).unique hf₀' - -- This follows by a bootstrapping formula expressing the derivative as a function of `f` itself - refine ⟨inverse ∘ f' ∘ f.symm, ?_, ?_⟩ - · -- We first check that the derivative of `f` is that formula - have h_nhds : { y : E | ∃ e : E ≃L[𝕜] F, ↑e = f' y } ∈ 𝓝 (f.symm a) := by - have hf₀' := f₀'.nhds - rw [← eq_f₀'] at hf₀' - exact hf'.continuousAt.preimage_mem_nhds hf₀' - obtain ⟨t, htu, ht, htf⟩ := mem_nhds_iff.mp (Filter.inter_mem hu h_nhds) - use f.target ∩ f.symm ⁻¹' t - refine ⟨IsOpen.mem_nhds ?_ ?_, ?_⟩ - · exact f.isOpen_inter_preimage_symm ht - · exact mem_inter ha (mem_preimage.mpr htf) - intro x hx - obtain ⟨hxu, e, he⟩ := htu hx.2 - have h_deriv : HasFDerivAt f (e : E →L[𝕜] F) (f.symm x) := by - rw [he] - exact hff' (f.symm x) hxu - convert f.hasFDerivAt_symm hx.1 h_deriv - simp [← he] - · -- Then we check that the formula, being a composition of `ContDiff` pieces, is - -- itself `ContDiff` - have h_deriv₁ : ContDiffAt 𝕜 n inverse (f' (f.symm a)) := by - rw [eq_f₀'] - exact contDiffAt_map_inverse _ - have h_deriv₂ : ContDiffAt 𝕜 n f.symm a := by - refine IH (hf.of_le ?_) - norm_cast - exact Nat.le_succ n - exact (h_deriv₁.comp _ hf').comp _ h_deriv₂ - · refine contDiffAt_top.mpr ?_ - intro n - exact Itop n (contDiffAt_top.mp hf n) - /-- If `f` is a local homeomorphism and the point `a` is in its target, and if `f` is `n` times continuously differentiable at `f.symm a`, and if the derivative at `f.symm a` is a continuous linear equivalence, @@ -1806,10 +1798,52 @@ theorem PartialHomeomorph.contDiffAt_symm [CompleteSpace E] (f : PartialHomeomor ContDiffAt 𝕜 n f.symm a := by match n with | ω => - intro k hk - exact f.contDiffAt_symm_aux ha hf₀' (hf.of_le (m := k) le_top) k le_rfl + apply AnalyticAt.contDiffAt + exact f.analyticAt_symm ha hf.analyticAt hf₀'.fderiv | (n : ℕ∞) => - exact f.contDiffAt_symm_aux ha hf₀' hf + -- We prove this by induction on `n` + induction' n using ENat.nat_induction with n IH Itop + · apply contDiffAt_zero.2 + exact ⟨f.target, IsOpen.mem_nhds f.open_target ha, f.continuousOn_invFun⟩ + · obtain ⟨f', ⟨u, hu, hff'⟩, hf'⟩ := contDiffAt_succ_iff_hasFDerivAt.mp hf + apply contDiffAt_succ_iff_hasFDerivAt.2 + -- For showing `n.succ` times continuous differentiability (the main inductive step), it + -- suffices to produce the derivative and show that it is `n` times continuously + -- differentiable + have eq_f₀' : f' (f.symm a) = f₀' := (hff' (f.symm a) (mem_of_mem_nhds hu)).unique hf₀' + -- This follows by a bootstrapping formula expressing the derivative as a + -- function of `f` itself + refine ⟨inverse ∘ f' ∘ f.symm, ?_, ?_⟩ + · -- We first check that the derivative of `f` is that formula + have h_nhds : { y : E | ∃ e : E ≃L[𝕜] F, ↑e = f' y } ∈ 𝓝 (f.symm a) := by + have hf₀' := f₀'.nhds + rw [← eq_f₀'] at hf₀' + exact hf'.continuousAt.preimage_mem_nhds hf₀' + obtain ⟨t, htu, ht, htf⟩ := mem_nhds_iff.mp (Filter.inter_mem hu h_nhds) + use f.target ∩ f.symm ⁻¹' t + refine ⟨IsOpen.mem_nhds ?_ ?_, ?_⟩ + · exact f.isOpen_inter_preimage_symm ht + · exact mem_inter ha (mem_preimage.mpr htf) + intro x hx + obtain ⟨hxu, e, he⟩ := htu hx.2 + have h_deriv : HasFDerivAt f (e : E →L[𝕜] F) (f.symm x) := by + rw [he] + exact hff' (f.symm x) hxu + convert f.hasFDerivAt_symm hx.1 h_deriv + simp [← he] + · -- Then we check that the formula, being a composition of `ContDiff` pieces, is + -- itself `ContDiff` + have h_deriv₁ : ContDiffAt 𝕜 n inverse (f' (f.symm a)) := by + rw [eq_f₀'] + exact contDiffAt_map_inverse _ + have h_deriv₂ : ContDiffAt 𝕜 n f.symm a := by + refine IH (hf.of_le ?_) + norm_cast + exact Nat.le_succ n + exact (h_deriv₁.comp _ hf').comp _ h_deriv₂ + · refine contDiffAt_infty.mpr ?_ + intro n + exact Itop n (contDiffAt_infty.mp hf n) /-- If `f` is an `n` times continuously differentiable homeomorphism, and if the derivative of `f` at each point is a continuous linear equivalence, @@ -1854,22 +1888,23 @@ variable (𝕜) 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`. -Note that `n` is a natural number, not `∞`, +Note that `n` is a natural number or `ω`, but not `∞`, because the set of points of `C^∞`-smoothness of `f` is not guaranteed to be open. -/ @[simps! apply symm_apply source target] -def restrContDiff (f : PartialHomeomorph E F) (n : ℕ) : PartialHomeomorph E F := +def restrContDiff (f : PartialHomeomorph E F) (n : WithTop ℕ∞) (hn : 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 _ ⟨hxs, hxf, hxf'⟩ ↦ - inter_mem (f.open_source.mem_nhds hxs) <| hxf.eventually.and <| - f.continuousAt hxs hxf'.eventually + inter_mem (f.open_source.mem_nhds hxs) <| (hxf.eventually hn).and <| + f.continuousAt hxs (hxf'.eventually hn) -lemma contDiffOn_restrContDiff_source (f : PartialHomeomorph E F) (n : ℕ) : - ContDiffOn 𝕜 n f (f.restrContDiff 𝕜 n).source := fun _x hx ↦ hx.2.1.contDiffWithinAt +lemma contDiffOn_restrContDiff_source (f : PartialHomeomorph E F) {n : WithTop ℕ∞} (hn : n ≠ ∞) : + ContDiffOn 𝕜 n f (f.restrContDiff 𝕜 n hn).source := fun _x hx ↦ hx.2.1.contDiffWithinAt -lemma contDiffOn_restrContDiff_target (f : PartialHomeomorph E F) (n : ℕ) : - ContDiffOn 𝕜 n f.symm (f.restrContDiff 𝕜 n).target := fun _x hx ↦ hx.2.1.contDiffWithinAt +lemma contDiffOn_restrContDiff_target (f : PartialHomeomorph E F) {n : WithTop ℕ∞} (hn : n ≠ ∞) : + ContDiffOn 𝕜 n f.symm (f.restrContDiff 𝕜 n hn).target := fun _x hx ↦ hx.2.1.contDiffWithinAt end PartialHomeomorph @@ -1892,19 +1927,22 @@ open ContinuousLinearMap (smulRight) /-- A function is `C^(n + 1)` on a domain with unique derivatives if and only if it is differentiable there, and its derivative (formulated with `derivWithin`) is `C^n`. -/ -theorem contDiffOn_succ_iff_derivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s₂) : +theorem contDiffOn_succ_iff_derivWithin (hs : UniqueDiffOn 𝕜 s₂) : ContDiffOn 𝕜 (n + 1) f₂ s₂ ↔ - DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 n (derivWithin f₂ s₂) s₂ := by + DifferentiableOn 𝕜 f₂ s₂ ∧ (n = ω → AnalyticOn 𝕜 f₂ s₂) ∧ + ContDiffOn 𝕜 n (derivWithin f₂ s₂) s₂ := by rw [contDiffOn_succ_iff_fderivWithin hs, and_congr_right_iff] intro _ constructor - · intro h + · rintro ⟨h', h⟩ + refine ⟨h', ?_⟩ have : derivWithin f₂ s₂ = (fun u : 𝕜 →L[𝕜] F => u 1) ∘ fderivWithin 𝕜 f₂ s₂ := by ext x; rfl simp_rw [this] apply ContDiff.comp_contDiffOn _ h exact (isBoundedBilinearMap_apply.isBoundedLinearMap_left _).contDiff - · intro h + · rintro ⟨h', h⟩ + refine ⟨h', ?_⟩ have : fderivWithin 𝕜 f₂ s₂ = smulRight (1 : 𝕜 →L[𝕜] 𝕜) ∘ derivWithin f₂ s₂ := by ext x; simp [derivWithin] simp only [this] @@ -1912,90 +1950,82 @@ theorem contDiffOn_succ_iff_derivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s₂) have : IsBoundedBilinearMap 𝕜 fun _ : (𝕜 →L[𝕜] 𝕜) × F => _ := isBoundedBilinearMap_smulRight exact (this.isBoundedLinearMap_right _).contDiff +theorem contDiffOn_infty_iff_derivWithin (hs : UniqueDiffOn 𝕜 s₂) : + ContDiffOn 𝕜 ∞ f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 ∞ (derivWithin f₂ s₂) s₂ := by + rw [show ∞ = ∞ + 1 by rfl, contDiffOn_succ_iff_derivWithin hs] + simp + +@[deprecated (since := "2024-11-27")] +alias contDiffOn_top_iff_derivWithin := contDiffOn_infty_iff_derivWithin + /-- A function is `C^(n + 1)` on an open domain if and only if it is differentiable there, and its derivative (formulated with `deriv`) is `C^n`. -/ -theorem contDiffOn_succ_iff_deriv_of_isOpen {n : ℕ} (hs : IsOpen s₂) : - ContDiffOn 𝕜 (n + 1) f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 n (deriv f₂) s₂ := by +theorem contDiffOn_succ_iff_deriv_of_isOpen (hs : IsOpen s₂) : + ContDiffOn 𝕜 (n + 1) f₂ s₂ ↔ + DifferentiableOn 𝕜 f₂ s₂ ∧ (n = ω → AnalyticOn 𝕜 f₂ s₂) ∧ + ContDiffOn 𝕜 n (deriv f₂) s₂ := by rw [contDiffOn_succ_iff_derivWithin hs.uniqueDiffOn] - exact Iff.rfl.and (contDiffOn_congr fun _ => derivWithin_of_isOpen hs) + exact Iff.rfl.and (Iff.rfl.and (contDiffOn_congr fun _ => derivWithin_of_isOpen hs)) -/-- A function is `C^∞` on a domain with unique derivatives if and only if it is differentiable -there, and its derivative (formulated with `derivWithin`) is `C^∞`. -/ -theorem contDiffOn_top_iff_derivWithin (hs : UniqueDiffOn 𝕜 s₂) : - ContDiffOn 𝕜 ∞ f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 ∞ (derivWithin f₂ s₂) s₂ := by - constructor - · intro h - refine ⟨h.differentiableOn (mod_cast le_top), ?_⟩ - refine contDiffOn_top.2 fun n => ((contDiffOn_succ_iff_derivWithin hs).1 ?_).2 - exact h.of_le (mod_cast le_top) - · intro h - refine contDiffOn_top.2 fun n => ?_ - have A : (n : ℕ∞) ≤ ∞ := mod_cast le_top - apply ((contDiffOn_succ_iff_derivWithin hs).2 ⟨h.1, h.2.of_le A⟩).of_le - exact_mod_cast (Nat.le_succ n) - -/-- A function is `C^∞` on an open domain if and only if it is differentiable -there, and its derivative (formulated with `deriv`) is `C^∞`. -/ -theorem contDiffOn_top_iff_deriv_of_isOpen (hs : IsOpen s₂) : +theorem contDiffOn_infty_iff_deriv_of_isOpen (hs : IsOpen s₂) : ContDiffOn 𝕜 ∞ f₂ s₂ ↔ DifferentiableOn 𝕜 f₂ s₂ ∧ ContDiffOn 𝕜 ∞ (deriv f₂) s₂ := by - rw [contDiffOn_top_iff_derivWithin hs.uniqueDiffOn] - exact Iff.rfl.and <| contDiffOn_congr fun _ => derivWithin_of_isOpen hs + rw [show ∞ = ∞ + 1 by rfl, contDiffOn_succ_iff_deriv_of_isOpen hs] + simp + +@[deprecated (since := "2024-11-27")] +alias contDiffOn_top_iff_deriv_of_isOpen := contDiffOn_infty_iff_deriv_of_isOpen protected theorem ContDiffOn.derivWithin (hf : ContDiffOn 𝕜 n f₂ s₂) (hs : UniqueDiffOn 𝕜 s₂) - (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (derivWithin f₂ s₂) s₂ := by - rcases le_or_lt ∞ n with hn | hn - · have : ContDiffOn 𝕜 ∞ (derivWithin f₂ s₂) s₂ := - ((contDiffOn_top_iff_derivWithin hs).1 (hf.of_le hn)).2 - intro x hx k hk - exact this x hx k (mod_cast le_top) - · match m with - | ω => simpa using hmn.trans_lt hn - | ∞ => simpa using hmn.trans_lt hn - | (m : ℕ) => - change (m.succ : ℕ∞) ≤ n at hmn - exact ((contDiffOn_succ_iff_derivWithin hs).1 (hf.of_le hmn)).2 + (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (derivWithin f₂ s₂) s₂ := + ((contDiffOn_succ_iff_derivWithin hs).1 (hf.of_le hmn)).2.2 theorem ContDiffOn.deriv_of_isOpen (hf : ContDiffOn 𝕜 n f₂ s₂) (hs : IsOpen s₂) (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (deriv f₂) s₂ := (hf.derivWithin hs.uniqueDiffOn hmn).congr fun _ hx => (derivWithin_of_isOpen hs hx).symm theorem ContDiffOn.continuousOn_derivWithin (h : ContDiffOn 𝕜 n f₂ s₂) (hs : UniqueDiffOn 𝕜 s₂) - (hn : 1 ≤ n) : ContinuousOn (derivWithin f₂ s₂) s₂ := - ((contDiffOn_succ_iff_derivWithin hs).1 (h.of_le hn)).2.continuousOn + (hn : 1 ≤ n) : ContinuousOn (derivWithin f₂ s₂) s₂ := by + rw [show (1 : WithTop ℕ∞) = 0 + 1 from rfl] at hn + exact ((contDiffOn_succ_iff_derivWithin hs).1 (h.of_le hn)).2.2.continuousOn theorem ContDiffOn.continuousOn_deriv_of_isOpen (h : ContDiffOn 𝕜 n f₂ s₂) (hs : IsOpen s₂) - (hn : 1 ≤ n) : ContinuousOn (deriv f₂) s₂ := - ((contDiffOn_succ_iff_deriv_of_isOpen hs).1 (h.of_le hn)).2.continuousOn + (hn : 1 ≤ n) : ContinuousOn (deriv f₂) s₂ := by + rw [show (1 : WithTop ℕ∞) = 0 + 1 from rfl] at hn + exact ((contDiffOn_succ_iff_deriv_of_isOpen hs).1 (h.of_le hn)).2.2.continuousOn /-- A function is `C^(n + 1)` if and only if it is differentiable, and its derivative (formulated in terms of `deriv`) is `C^n`. -/ -theorem contDiff_succ_iff_deriv {n : ℕ} : - ContDiff 𝕜 (n + 1) f₂ ↔ Differentiable 𝕜 f₂ ∧ ContDiff 𝕜 n (deriv f₂) := by +theorem contDiff_succ_iff_deriv : + ContDiff 𝕜 (n + 1) f₂ ↔ Differentiable 𝕜 f₂ ∧ (n = ω → AnalyticOn 𝕜 f₂ univ) ∧ + ContDiff 𝕜 n (deriv f₂) := by simp only [← contDiffOn_univ, contDiffOn_succ_iff_deriv_of_isOpen, isOpen_univ, differentiableOn_univ] -theorem contDiff_one_iff_deriv : ContDiff 𝕜 1 f₂ ↔ Differentiable 𝕜 f₂ ∧ Continuous (deriv f₂) := - contDiff_succ_iff_deriv.trans <| Iff.rfl.and contDiff_zero +theorem contDiff_one_iff_deriv : + ContDiff 𝕜 1 f₂ ↔ Differentiable 𝕜 f₂ ∧ Continuous (deriv f₂) := by + rw [show (1 : WithTop ℕ∞) = 0 + 1 from rfl, contDiff_succ_iff_deriv] + simp -/-- A function is `C^∞` if and only if it is differentiable, -and its derivative (formulated in terms of `deriv`) is `C^∞`. -/ -theorem contDiff_top_iff_deriv : +theorem contDiff_infty_iff_deriv : ContDiff 𝕜 ∞ f₂ ↔ Differentiable 𝕜 f₂ ∧ ContDiff 𝕜 ∞ (deriv f₂) := by - simp only [← contDiffOn_univ, ← differentiableOn_univ, ← derivWithin_univ] - rw [contDiffOn_top_iff_derivWithin uniqueDiffOn_univ] + rw [show (∞ : WithTop ℕ∞) = ∞ + 1 from rfl, contDiff_succ_iff_deriv] + simp + +@[deprecated (since := "2024-11-27")] alias contDiff_top_iff_deriv := contDiff_infty_iff_deriv -theorem ContDiff.continuous_deriv (h : ContDiff 𝕜 n f₂) (hn : 1 ≤ n) : Continuous (deriv f₂) := - (contDiff_succ_iff_deriv.mp (h.of_le hn)).2.continuous +theorem ContDiff.continuous_deriv (h : ContDiff 𝕜 n f₂) (hn : 1 ≤ n) : Continuous (deriv f₂) := by + rw [show (1 : WithTop ℕ∞) = 0 + 1 from rfl] at hn + exact (contDiff_succ_iff_deriv.mp (h.of_le hn)).2.2.continuous theorem ContDiff.iterate_deriv : ∀ (n : ℕ) {f₂ : 𝕜 → F}, ContDiff 𝕜 ∞ f₂ → ContDiff 𝕜 ∞ (deriv^[n] f₂) | 0, _, hf => hf - | n + 1, _, hf => ContDiff.iterate_deriv n (contDiff_top_iff_deriv.mp hf).2 + | n + 1, _, hf => ContDiff.iterate_deriv n (contDiff_infty_iff_deriv.mp hf).2 theorem ContDiff.iterate_deriv' (n : ℕ) : ∀ (k : ℕ) {f₂ : 𝕜 → F}, ContDiff 𝕜 (n + k : ℕ) f₂ → ContDiff 𝕜 n (deriv^[k] f₂) | 0, _, hf => hf - | k + 1, _, hf => ContDiff.iterate_deriv' _ k (contDiff_succ_iff_deriv.mp hf).2 + | k + 1, _, hf => ContDiff.iterate_deriv' _ k (contDiff_succ_iff_deriv.mp hf).2.2 end deriv @@ -2029,9 +2059,18 @@ theorem HasFTaylorSeriesUpToOn.restrictScalars {n : WithTop ℕ∞} cont m hm := ContinuousMultilinearMap.continuous_restrictScalars.comp_continuousOn (h.cont m hm) theorem ContDiffWithinAt.restrict_scalars (h : ContDiffWithinAt 𝕜' n f s x) : - ContDiffWithinAt 𝕜 n f s x := fun m hm ↦ by - rcases h m hm with ⟨u, u_mem, p', hp'⟩ - exact ⟨u, u_mem, _, hp'.restrictScalars _⟩ + ContDiffWithinAt 𝕜 n f s x := by + match n with + | ω => + obtain ⟨u, u_mem, p', hp', Hp'⟩ := h + refine ⟨u, u_mem, _, hp'.restrictScalars _, fun i ↦ ?_⟩ + change AnalyticOn 𝕜 (fun x ↦ ContinuousMultilinearMap.restrictScalarsLinear 𝕜 (p' x i)) u + apply AnalyticOnNhd.comp_analyticOn _ (Hp' i).restrictScalars (Set.mapsTo_univ _ _) + exact ContinuousLinearMap.analyticOnNhd _ _ + | (n : ℕ∞) => + intro m hm + rcases h m hm with ⟨u, u_mem, p', hp'⟩ + exact ⟨u, u_mem, _, hp'.restrictScalars _⟩ theorem ContDiffOn.restrict_scalars (h : ContDiffOn 𝕜' n f s) : ContDiffOn 𝕜 n f s := fun x hx => (h x hx).restrict_scalars _ diff --git a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean index fe52bff69b40d..008902d921c30 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Bounds.lean @@ -152,12 +152,12 @@ theorem ContinuousLinearMap.norm_iteratedFDerivWithin_le_of_bilinear (B : E →L (ContinuousLinearMap.compL 𝕜 Fu G Gu (isoG.symm : G →L[𝕜] Gu)) Bu₀ := rfl have Bu_eq : (fun y => Bu (fu y) (gu y)) = isoG.symm ∘ (fun y => B (f y) (g y)) ∘ isoD := by ext1 y - simp [hBu, hBu₀, hfu, hgu] + simp [Du, Eu, Fu, Gu, hBu, hBu₀, hfu, hgu] -- All norms are preserved by the lifting process. have Bu_le : ‖Bu‖ ≤ ‖B‖ := by refine ContinuousLinearMap.opNorm_le_bound _ (norm_nonneg B) fun y => ?_ refine ContinuousLinearMap.opNorm_le_bound _ (by positivity) fun x => ?_ - simp only [hBu, hBu₀, compL_apply, coe_comp', Function.comp_apply, + simp only [Du, Eu, Fu, Gu, hBu, hBu₀, compL_apply, coe_comp', Function.comp_apply, ContinuousLinearEquiv.coe_coe, LinearIsometryEquiv.coe_coe, flip_apply, LinearIsometryEquiv.norm_map] calc diff --git a/Mathlib/Analysis/Calculus/ContDiff/CPolynomial.lean b/Mathlib/Analysis/Calculus/ContDiff/CPolynomial.lean index 3a66c7c3d570a..ebd550a6c8643 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/CPolynomial.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/CPolynomial.lean @@ -15,7 +15,7 @@ of continuous multilinear maps. open Filter Asymptotics -open scoped ENNReal ContDiff +open scoped ENNReal universe u v @@ -32,15 +32,12 @@ variable {f : E → F} {x : E} {s : Set E} theorem CPolynomialOn.contDiffOn (h : CPolynomialOn 𝕜 f s) {n : WithTop ℕ∞} : ContDiffOn 𝕜 n f s := by let t := { x | CPolynomialAt 𝕜 f x } - suffices ContDiffOn 𝕜 ω f t from (this.of_le le_top).mono h - rw [← contDiffOn_infty_iff_contDiffOn_omega] + suffices ContDiffOn 𝕜 n f t from this.mono h + suffices AnalyticOnNhd 𝕜 f t by + have t_open : IsOpen t := isOpen_cPolynomialAt 𝕜 f + exact AnalyticOnNhd.contDiffOn this t_open.uniqueDiffOn have H : CPolynomialOn 𝕜 f t := fun _x hx ↦ hx - have t_open : IsOpen t := isOpen_cPolynomialAt 𝕜 f - exact contDiffOn_of_continuousOn_differentiableOn - (fun m _ ↦ (H.iteratedFDeriv m).continuousOn.congr - fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) - (fun m _ ↦ (H.iteratedFDeriv m).analyticOnNhd.differentiableOn.congr - fun _ hx ↦ iteratedFDerivWithin_of_isOpen _ t_open hx) + exact H.analyticOnNhd theorem CPolynomialAt.contDiffAt (h : CPolynomialAt 𝕜 f x) {n : WithTop ℕ∞} : ContDiffAt 𝕜 n f x := diff --git a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean index 180ea22be1a5e..e772546295c8f 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/Defs.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/Defs.lean @@ -3,6 +3,8 @@ Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ +import Mathlib.Analysis.Analytic.Within +import Mathlib.Analysis.Calculus.FDeriv.Analytic import Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries /-! @@ -11,7 +13,9 @@ import Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries A function is `C^1` on a domain if it is differentiable there, and its derivative is continuous. By induction, it is `C^n` if it is `C^{n-1}` and its (n-1)-th derivative is `C^1` there or, equivalently, if it is `C^1` and its derivative is `C^{n-1}`. -Finally, it is `C^∞` if it is `C^n` for all n. +It is `C^∞` if it is `C^n` for all n. +Finally, it is `C^ω` if it is analytic (as well as all its derivative, which is automatic if the +space is complete). We formalize these notions with predicates `ContDiffWithinAt`, `ContDiffAt`, `ContDiffOn` and `ContDiff` saying that the function is `C^n` within a set at a point, at a point, on a set @@ -81,7 +85,9 @@ a neighborhood of `x` within `s ∪ {x}` (which appears as `insert x s` in this We use the notation `E [×n]→L[𝕜] F` for the space of continuous multilinear maps on `E^n` with values in `F`. This is the space in which the `n`-th derivative of a function from `E` to `F` lives. -In this file, we denote `⊤ : ℕ∞` with `∞`. +In this file, we denote `(⊤ : ℕ∞) : WithTop ℕ∞` with `∞`, and `⊤ : WithTop ℕ∞` with `ω`. To +avoid ambiguities with the two tops, the theorems name use either `infty` or `omega`. +These notations are scoped in `ContDiff`. ## Tags @@ -93,14 +99,6 @@ noncomputable section open scoped Classical open NNReal Topology Filter -/-- Smoothness exponent for analytic functions. Not implemented yet, `ω` smoothness is equivalent -to `∞` smoothness in current mathlib. -/ -scoped [ContDiff] notation3 "ω" => (⊤ : WithTop ℕ∞) -/-- Smoothness exponent for infinitely differentiable functions. -/ -scoped [ContDiff] notation3 "∞" => ((⊤ : ℕ∞) : WithTop ℕ∞) - -open ContDiff - /- Porting note: These lines are not required in Mathlib4. attribute [local instance 1001] @@ -109,6 +107,8 @@ attribute [local instance 1001] open Set Fin Filter Function +open scoped ContDiff + universe u uE uF uG uX variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAddCommGroup E] @@ -119,51 +119,119 @@ variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {E : Type uE} [NormedAdd /-! ### Smooth functions within a set around a point -/ -variable (𝕜) - +variable (𝕜) in /-- A function is continuously differentiable up to order `n` within a set `s` at a point `x` if it admits continuous derivatives up to order `n` in a neighborhood of `x` in `s ∪ {x}`. For `n = ∞`, we only require that this holds up to any finite order (where the neighborhood may depend on the finite order we consider). +For `n = ω`, we require the function to be analytic within `s` at `x`. The precise definition we +give (all the derivatives should be analytic) is more involved to work around issues when the space +is not complete, but it is equivalent when the space is complete. For instance, a real function which is `C^m` on `(-1/m, 1/m)` for each natural `m`, but not better, is `C^∞` at `0` within `univ`. - -We take the exponent `n` in `WithTop ℕ∞` to allow for an extension to analytic functions in the -future, but currently the notion is the same for `n = ∞` and `n = ω`. -/ def ContDiffWithinAt (n : WithTop ℕ∞) (f : E → F) (s : Set E) (x : E) : Prop := - ∀ m : ℕ, m ≤ n → ∃ u ∈ 𝓝[insert x s] x, - ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn m f p u - -variable {𝕜} + match n with + | ω => ∃ u ∈ 𝓝[insert x s] x, ∃ p : E → FormalMultilinearSeries 𝕜 E F, + HasFTaylorSeriesUpToOn ω f p u ∧ ∀ i, AnalyticOn 𝕜 (fun x ↦ p x i) u + | (n : ℕ∞) => ∀ m : ℕ, m ≤ n → ∃ u ∈ 𝓝[insert x s] x, + ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn m f p u + +lemma HasFTaylorSeriesUpToOn.analyticOn + (hf : HasFTaylorSeriesUpToOn ω f p s) (h : AnalyticOn 𝕜 (fun x ↦ p x 0) s) : + AnalyticOn 𝕜 f s := by + have : AnalyticOn 𝕜 (fun x ↦ (continuousMultilinearCurryFin0 𝕜 E F) (p x 0)) s := + (LinearIsometryEquiv.analyticOnNhd _ _ ).comp_analyticOn + h (Set.mapsTo_univ _ _) + exact this.congr (fun y hy ↦ (hf.zero_eq _ hy).symm) + +lemma ContDiffWithinAt.analyticOn (h : ContDiffWithinAt 𝕜 ω f s x) : + ∃ u ∈ 𝓝[insert x s] x, AnalyticOn 𝕜 f u := by + obtain ⟨u, hu, p, hp, h'p⟩ := h + exact ⟨u, hu, hp.analyticOn (h'p 0)⟩ + +lemma ContDiffWithinAt.analyticWithinAt (h : ContDiffWithinAt 𝕜 ω f s x) : + AnalyticWithinAt 𝕜 f s x := by + obtain ⟨u, hu, hf⟩ := h.analyticOn + have xu : x ∈ u := mem_of_mem_nhdsWithin (by simp) hu + exact (hf x xu).mono_of_mem_nhdsWithin (nhdsWithin_mono _ (subset_insert _ _) hu) + +theorem contDiffWithinAt_omega_iff_analyticWithinAt [CompleteSpace F] : + ContDiffWithinAt 𝕜 ω f s x ↔ AnalyticWithinAt 𝕜 f s x := by + refine ⟨fun h ↦ h.analyticWithinAt, fun h ↦ ?_⟩ + obtain ⟨u, hu, p, hp, h'p⟩ := h.exists_hasFTaylorSeriesUpToOn ω + exact ⟨u, hu, p, hp.of_le le_top, fun i ↦ h'p i⟩ theorem contDiffWithinAt_nat {n : ℕ} : ContDiffWithinAt 𝕜 n f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn n f p u := ⟨fun H => H n le_rfl, fun ⟨u, hu, p, hp⟩ _m hm => ⟨u, hu, p, hp.of_le (mod_cast hm)⟩⟩ +/-- When `n` is either a natural number or `ω`, one can characterize the property of being `C^n` +as the existence of a neighborhood on which there is a Taylor series up to order `n`, +requiring in addition that its terms are analytic in the `ω` case. -/ +lemma contDiffWithinAt_iff_of_ne_infty (hn : n ≠ ∞) : + ContDiffWithinAt 𝕜 n f s x ↔ ∃ u ∈ 𝓝[insert x s] x, + ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpToOn n f p u ∧ + (n = ω → ∀ i, AnalyticOn 𝕜 (fun x ↦ p x i) u) := by + match n with + | ω => simp [ContDiffWithinAt] + | ∞ => simp at hn + | (n : ℕ) => simp [contDiffWithinAt_nat] + theorem ContDiffWithinAt.of_le (h : ContDiffWithinAt 𝕜 n f s x) (hmn : m ≤ n) : - ContDiffWithinAt 𝕜 m f s x := fun k hk => h k (le_trans hk hmn) + ContDiffWithinAt 𝕜 m f s x := by + match n with + | ω => match m with + | ω => exact h + | (m : ℕ∞) => + intro k _ + obtain ⟨u, hu, p, hp, -⟩ := h + exact ⟨u, hu, p, hp.of_le le_top⟩ + | (n : ℕ∞) => match m with + | ω => simp at hmn + | (m : ℕ∞) => exact fun k hk ↦ h k (le_trans hk (mod_cast hmn)) + +/-- In a complete space, a function which is analytic within a set at a point is also `C^ω` there. +Note that the same statement for `AnalyticOn` does not require completeness, see +`AnalyticOn.contDiffOn`. -/ +theorem AnalyticWithinAt.contDiffWithinAt [CompleteSpace F] (h : AnalyticWithinAt 𝕜 f s x) : + ContDiffWithinAt 𝕜 n f s x := + (contDiffWithinAt_omega_iff_analyticWithinAt.2 h).of_le le_top theorem contDiffWithinAt_iff_forall_nat_le {n : ℕ∞} : ContDiffWithinAt 𝕜 n f s x ↔ ∀ m : ℕ, ↑m ≤ n → ContDiffWithinAt 𝕜 m f s x := - ⟨fun H _m hm => H.of_le (mod_cast hm), fun H m hm => H m (mod_cast hm) _ le_rfl⟩ + ⟨fun H _ hm => H.of_le (mod_cast hm), fun H m hm => H m hm _ le_rfl⟩ -theorem contDiffWithinAt_top : ContDiffWithinAt 𝕜 ∞ f s x ↔ ∀ n : ℕ, ContDiffWithinAt 𝕜 n f s x := +theorem contDiffWithinAt_infty : + ContDiffWithinAt 𝕜 ∞ f s x ↔ ∀ n : ℕ, ContDiffWithinAt 𝕜 n f s x := contDiffWithinAt_iff_forall_nat_le.trans <| by simp only [forall_prop_of_true, le_top] +@[deprecated (since := "2024-11-25")] alias contDiffWithinAt_top := contDiffWithinAt_infty + theorem ContDiffWithinAt.continuousWithinAt (h : ContDiffWithinAt 𝕜 n f s x) : ContinuousWithinAt f s x := by - rcases h 0 bot_le with ⟨u, hu, p, H⟩ + have := h.of_le (zero_le _) + simp only [ContDiffWithinAt, nonpos_iff_eq_zero, Nat.cast_eq_zero, + mem_pure, forall_eq, CharP.cast_eq_zero] at this + rcases this with ⟨u, hu, p, H⟩ rw [mem_nhdsWithin_insert] at hu exact (H.continuousOn.continuousWithinAt hu.1).mono_of_mem_nhdsWithin hu.2 theorem ContDiffWithinAt.congr_of_eventuallyEq (h : ContDiffWithinAt 𝕜 n f s x) - (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : ContDiffWithinAt 𝕜 n f₁ s x := fun m hm => - let ⟨u, hu, p, H⟩ := h m hm - ⟨{ x ∈ u | f₁ x = f x }, Filter.inter_mem hu (mem_nhdsWithin_insert.2 ⟨hx, h₁⟩), p, - (H.mono (sep_subset _ _)).congr fun _ => And.right⟩ + (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : ContDiffWithinAt 𝕜 n f₁ s x := by + match n with + | ω => + obtain ⟨u, hu, p, H, H'⟩ := h + exact ⟨{x ∈ u | f₁ x = f x}, Filter.inter_mem hu (mem_nhdsWithin_insert.2 ⟨hx, h₁⟩), p, + (H.mono (sep_subset _ _)).congr fun _ ↦ And.right, + fun i ↦ (H' i).mono (sep_subset _ _)⟩ + | (n : ℕ∞) => + intro m hm + let ⟨u, hu, p, H⟩ := h m hm + exact ⟨{ x ∈ u | f₁ x = f x }, Filter.inter_mem hu (mem_nhdsWithin_insert.2 ⟨hx, h₁⟩), p, + (H.mono (sep_subset _ _)).congr fun _ ↦ And.right⟩ theorem Filter.EventuallyEq.congr_contDiffWithinAt (h₁ : f₁ =ᶠ[𝓝[s] x] f) (hx : f₁ x = f x) : ContDiffWithinAt 𝕜 n f₁ s x ↔ ContDiffWithinAt 𝕜 n f s x := @@ -221,9 +289,14 @@ theorem contDiffWithinAt_congr_of_insert (h₁ : ∀ y ∈ insert x s, f₁ y = theorem ContDiffWithinAt.mono_of_mem_nhdsWithin (h : ContDiffWithinAt 𝕜 n f s x) {t : Set E} (hst : s ∈ 𝓝[t] x) : ContDiffWithinAt 𝕜 n f t x := by - intro m hm - rcases h m hm with ⟨u, hu, p, H⟩ - exact ⟨u, nhdsWithin_le_of_mem (insert_mem_nhdsWithin_insert hst) hu, p, H⟩ + match n with + | ω => + obtain ⟨u, hu, p, H, H'⟩ := h + exact ⟨u, nhdsWithin_le_of_mem (insert_mem_nhdsWithin_insert hst) hu, p, H, H'⟩ + | (n : ℕ∞) => + intro m hm + rcases h m hm with ⟨u, hu, p, H⟩ + exact ⟨u, nhdsWithin_le_of_mem (insert_mem_nhdsWithin_insert hst) hu, p, H⟩ @[deprecated (since := "2024-10-30")] alias ContDiffWithinAt.mono_of_mem := ContDiffWithinAt.mono_of_mem_nhdsWithin @@ -262,13 +335,17 @@ theorem contDiffWithinAt_inter (h : t ∈ 𝓝 x) : theorem contDiffWithinAt_insert_self : ContDiffWithinAt 𝕜 n f (insert x s) x ↔ ContDiffWithinAt 𝕜 n f s x := by - simp_rw [ContDiffWithinAt, insert_idem] + match n with + | ω => simp [ContDiffWithinAt] + | (n : ℕ∞) => simp_rw [ContDiffWithinAt, insert_idem] theorem contDiffWithinAt_insert {y : E} : ContDiffWithinAt 𝕜 n f (insert y s) x ↔ ContDiffWithinAt 𝕜 n f s x := by - rcases eq_or_ne x y with (rfl | h) + rcases eq_or_ne x y with (rfl | hx) · exact contDiffWithinAt_insert_self - simp_rw [ContDiffWithinAt, insert_comm x y, nhdsWithin_insert_of_ne h] + refine ⟨fun h ↦ h.mono (subset_insert _ _), fun h ↦ ?_⟩ + apply h.mono_of_mem_nhdsWithin + simp [nhdsWithin_insert_of_ne hx, self_mem_nhdsWithin] alias ⟨ContDiffWithinAt.of_insert, ContDiffWithinAt.insert'⟩ := contDiffWithinAt_insert @@ -284,7 +361,7 @@ theorem contDiffWithinAt_diff_singleton {y : E} : within this set at this point. -/ theorem ContDiffWithinAt.differentiableWithinAt' (h : ContDiffWithinAt 𝕜 n f s x) (hn : 1 ≤ n) : DifferentiableWithinAt 𝕜 f (insert x s) x := by - rcases h 1 hn with ⟨u, hu, p, H⟩ + rcases contDiffWithinAt_nat.1 (h.of_le hn) with ⟨u, hu, p, H⟩ rcases mem_nhdsWithin.1 hu with ⟨t, t_open, xt, tu⟩ rw [inter_comm] at tu exact (differentiableWithinAt_inter (IsOpen.mem_nhds t_open xt)).1 <| @@ -297,34 +374,42 @@ theorem ContDiffWithinAt.differentiableWithinAt (h : ContDiffWithinAt 𝕜 n f s DifferentiableWithinAt 𝕜 f s x := (h.differentiableWithinAt' hn).mono (subset_insert x s) -/-- A function is `C^(n + 1)` on a domain iff locally, it has a derivative which is `C^n`. -/ -theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt {n : ℕ} : - ContDiffWithinAt 𝕜 (n + 1) f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ∃ f' : E → E →L[𝕜] F, +/-- A function is `C^(n + 1)` on a domain iff locally, it has a derivative which is `C^n` +(and moreover the function is analytic when `n = ω`). -/ +theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt (hn : n ≠ ∞) : + ContDiffWithinAt 𝕜 (n + 1) f s x ↔ ∃ u ∈ 𝓝[insert x s] x, (n = ω → AnalyticOn 𝕜 f u) ∧ + ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) u x) ∧ ContDiffWithinAt 𝕜 n f' u x := by + have h'n : n + 1 ≠ ∞ := by simpa using hn constructor · intro h - rcases h n.succ le_rfl with ⟨u, hu, p, Hp⟩ - refine - ⟨u, hu, fun y => (continuousMultilinearCurryFin1 𝕜 E F) (p y 1), fun y hy => - Hp.hasFDerivWithinAt (mod_cast (Nat.le_add_left 1 n)) hy, ?_⟩ - intro m hm + rcases (contDiffWithinAt_iff_of_ne_infty h'n).1 h with ⟨u, hu, p, Hp, H'p⟩ + refine ⟨u, hu, ?_, fun y => (continuousMultilinearCurryFin1 𝕜 E F) (p y 1), + fun y hy => Hp.hasFDerivWithinAt le_add_self hy, ?_⟩ + · rintro rfl + exact Hp.analyticOn (H'p rfl 0) + apply (contDiffWithinAt_iff_of_ne_infty hn).2 refine ⟨u, ?_, fun y : E => (p y).shift, ?_⟩ · -- Porting note: without the explicit argument Lean is not sure of the type. convert @self_mem_nhdsWithin _ _ x u have : x ∈ insert x s := by simp exact insert_eq_of_mem (mem_of_mem_nhdsWithin this hu) - · rw [show ((n.succ : ℕ) : WithTop ℕ∞) = n + 1 from rfl, - hasFTaylorSeriesUpToOn_succ_iff_right] at Hp - exact Hp.2.2.of_le (mod_cast hm) - · rintro ⟨u, hu, f', f'_eq_deriv, Hf'⟩ - rw [show (n : WithTop ℕ∞) + 1 = (n + 1 : ℕ) from rfl, contDiffWithinAt_nat] - rcases Hf' n le_rfl with ⟨v, hv, p', Hp'⟩ - refine ⟨v ∩ u, ?_, fun x => (p' x).unshift (f x), ?_⟩ + · rw [hasFTaylorSeriesUpToOn_succ_iff_right] at Hp + refine ⟨Hp.2.2, ?_⟩ + rintro rfl i + change AnalyticOn 𝕜 + (fun x ↦ (continuousMultilinearCurryRightEquiv' 𝕜 i E F) (p x (i + 1))) u + apply (LinearIsometryEquiv.analyticOnNhd _ _).comp_analyticOn + ?_ (Set.mapsTo_univ _ _) + exact H'p rfl _ + · rintro ⟨u, hu, hf, f', f'_eq_deriv, Hf'⟩ + rw [contDiffWithinAt_iff_of_ne_infty h'n] + rcases (contDiffWithinAt_iff_of_ne_infty hn).1 Hf' with ⟨v, hv, p', Hp', p'_an⟩ + refine ⟨v ∩ u, ?_, fun x => (p' x).unshift (f x), ?_, ?_⟩ · apply Filter.inter_mem _ hu apply nhdsWithin_le_of_mem hu exact nhdsWithin_mono _ (subset_insert x u) hv - · rw [show ((n.succ : ℕ) : WithTop ℕ∞) = n + 1 from rfl, - hasFTaylorSeriesUpToOn_succ_iff_right] + · rw [hasFTaylorSeriesUpToOn_succ_iff_right] refine ⟨fun y _ => rfl, fun y hy => ?_, ?_⟩ · change HasFDerivWithinAt (fun z => (continuousMultilinearCurryFin0 𝕜 E F).symm (f z)) @@ -347,32 +432,48 @@ theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt {n : ℕ} : change p' x k (init (@snoc k (fun _ : Fin k.succ => E) v y)) (@snoc k (fun _ : Fin k.succ => E) v y (last k)) = p' x k v y rw [snoc_last, init_snoc] + · intro h i + simp only [WithTop.add_eq_top, WithTop.one_ne_top, or_false] at h + match i with + | 0 => + simp only [FormalMultilinearSeries.unshift] + apply AnalyticOnNhd.comp_analyticOn _ ((hf h).mono inter_subset_right) + (Set.mapsTo_univ _ _) + exact LinearIsometryEquiv.analyticOnNhd _ _ + | i + 1 => + simp only [FormalMultilinearSeries.unshift, Nat.succ_eq_add_one] + apply AnalyticOnNhd.comp_analyticOn _ ((p'_an h i).mono inter_subset_left) + (Set.mapsTo_univ _ _) + exact LinearIsometryEquiv.analyticOnNhd _ _ /-- A version of `contDiffWithinAt_succ_iff_hasFDerivWithinAt` where all derivatives are taken within the same set. -/ -theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt' {n : ℕ} : +theorem contDiffWithinAt_succ_iff_hasFDerivWithinAt' (hn : n ≠ ∞) : ContDiffWithinAt 𝕜 (n + 1) f s x ↔ - ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ ∃ f' : E → E →L[𝕜] F, + ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ (n = ω → AnalyticOn 𝕜 f u) ∧ + ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) s x) ∧ ContDiffWithinAt 𝕜 n f' s x := by refine ⟨fun hf => ?_, ?_⟩ - · obtain ⟨u, hu, f', huf', hf'⟩ := contDiffWithinAt_succ_iff_hasFDerivWithinAt.mp hf + · obtain ⟨u, hu, f_an, f', huf', hf'⟩ := (contDiffWithinAt_succ_iff_hasFDerivWithinAt hn).mp hf obtain ⟨w, hw, hxw, hwu⟩ := mem_nhdsWithin.mp hu rw [inter_comm] at hwu - refine ⟨insert x s ∩ w, inter_mem_nhdsWithin _ (hw.mem_nhds hxw), inter_subset_left, f', + refine ⟨insert x s ∩ w, inter_mem_nhdsWithin _ (hw.mem_nhds hxw), inter_subset_left, ?_, f', fun y hy => ?_, ?_⟩ + · intro h + apply (f_an h).mono hwu · refine ((huf' y <| hwu hy).mono hwu).mono_of_mem_nhdsWithin ?_ refine mem_of_superset ?_ (inter_subset_inter_left _ (subset_insert _ _)) exact inter_mem_nhdsWithin _ (hw.mem_nhds hy.2) · exact hf'.mono_of_mem_nhdsWithin (nhdsWithin_mono _ (subset_insert _ _) hu) - · rw [← contDiffWithinAt_insert, contDiffWithinAt_succ_iff_hasFDerivWithinAt, + · rw [← contDiffWithinAt_insert, contDiffWithinAt_succ_iff_hasFDerivWithinAt hn, insert_eq_of_mem (mem_insert _ _)] - rintro ⟨u, hu, hus, f', huf', hf'⟩ - exact ⟨u, hu, f', fun y hy => (huf' y hy).insert'.mono hus, hf'.insert.mono hus⟩ + rintro ⟨u, hu, hus, f_an, f', huf', hf'⟩ + exact ⟨u, hu, f_an, f', fun y hy => (huf' y hy).insert'.mono hus, hf'.insert.mono hus⟩ -/-! ### Smooth functions within a set -/ -variable (𝕜) +/-! ### Smooth functions within a set -/ +variable (𝕜) in /-- A function is continuously differentiable up to `n` on `s` if, for any point `x` in `s`, it admits continuous derivatives up to order `n` on a neighborhood of `x` in `s`. @@ -382,9 +483,7 @@ depend on the finite order we consider). def ContDiffOn (n : WithTop ℕ∞) (f : E → F) (s : Set E) : Prop := ∀ x ∈ s, ContDiffWithinAt 𝕜 n f s x -variable {𝕜} - -theorem HasFTaylorSeriesUpToOn.contDiffOn {f' : E → FormalMultilinearSeries 𝕜 E F} +theorem HasFTaylorSeriesUpToOn.contDiffOn {n : ℕ∞} {f' : E → FormalMultilinearSeries 𝕜 E F} (hf : HasFTaylorSeriesUpToOn n f f' s) : ContDiffOn 𝕜 n f s := by intro x hx m hm use s @@ -395,59 +494,80 @@ theorem ContDiffOn.contDiffWithinAt (h : ContDiffOn 𝕜 n f s) (hx : x ∈ s) : ContDiffWithinAt 𝕜 n f s x := h x hx -theorem ContDiffWithinAt.contDiffOn' {m : ℕ} (hm : m ≤ n) +theorem ContDiffOn.of_le (h : ContDiffOn 𝕜 n f s) (hmn : m ≤ n) : ContDiffOn 𝕜 m f s := fun x hx => + (h x hx).of_le hmn + +theorem ContDiffWithinAt.contDiffOn' (hm : m ≤ n) (h' : m = ∞ → n = ω) (h : ContDiffWithinAt 𝕜 n f s x) : ∃ u, IsOpen u ∧ x ∈ u ∧ ContDiffOn 𝕜 m f (insert x s ∩ u) := by - rcases h m hm with ⟨t, ht, p, hp⟩ - rcases mem_nhdsWithin.1 ht with ⟨u, huo, hxu, hut⟩ - rw [inter_comm] at hut - exact ⟨u, huo, hxu, (hp.mono hut).contDiffOn⟩ + rcases eq_or_ne n ω with rfl | hn + · obtain ⟨t, ht, p, hp, h'p⟩ := h + rcases mem_nhdsWithin.1 ht with ⟨u, huo, hxu, hut⟩ + rw [inter_comm] at hut + refine ⟨u, huo, hxu, ?_⟩ + suffices ContDiffOn 𝕜 ω f (insert x s ∩ u) from this.of_le le_top + intro y hy + refine ⟨insert x s ∩ u, ?_, p, hp.mono hut, fun i ↦ (h'p i).mono hut⟩ + simp only [insert_eq_of_mem, hy, self_mem_nhdsWithin] + · match m with + | ω => simp [hn] at hm + | ∞ => exact (hn (h' rfl)).elim + | (m : ℕ) => + rcases contDiffWithinAt_nat.1 (h.of_le hm) with ⟨t, ht, p, hp⟩ + rcases mem_nhdsWithin.1 ht with ⟨u, huo, hxu, hut⟩ + rw [inter_comm] at hut + exact ⟨u, huo, hxu, (hp.mono hut).contDiffOn⟩ + +theorem ContDiffWithinAt.contDiffOn (hm : m ≤ n) (h' : m = ∞ → n = ω) + (h : ContDiffWithinAt 𝕜 n f s x) : + ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ ContDiffOn 𝕜 m f u := by + obtain ⟨_u, uo, xu, h⟩ := h.contDiffOn' hm h' + exact ⟨_, inter_mem_nhdsWithin _ (uo.mem_nhds xu), inter_subset_left, h⟩ -theorem ContDiffWithinAt.contDiffOn {m : ℕ} (hm : m ≤ n) (h : ContDiffWithinAt 𝕜 n f s x) : - ∃ u ∈ 𝓝[insert x s] x, u ⊆ insert x s ∧ ContDiffOn 𝕜 m f u := - let ⟨_u, uo, xu, h⟩ := h.contDiffOn' hm - ⟨_, inter_mem_nhdsWithin _ (uo.mem_nhds xu), inter_subset_left, h⟩ +theorem ContDiffOn.analyticOn (h : ContDiffOn 𝕜 ω f s) : AnalyticOn 𝕜 f s := + fun x hx ↦ (h x hx).analyticWithinAt /-- A function is `C^n` within a set at a point, for `n : ℕ`, if and only if it is `C^n` on a neighborhood of this point. -/ -theorem contDiffWithinAt_iff_contDiffOn_nhds {n : ℕ} : +theorem contDiffWithinAt_iff_contDiffOn_nhds (hn : n ≠ ∞) : ContDiffWithinAt 𝕜 n f s x ↔ ∃ u ∈ 𝓝[insert x s] x, ContDiffOn 𝕜 n f u := by refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ - · rcases h.contDiffOn le_rfl with ⟨u, hu, h'u⟩ + · rcases h.contDiffOn le_rfl (by simp [hn]) with ⟨u, hu, h'u⟩ exact ⟨u, hu, h'u.2⟩ · rcases h with ⟨u, u_mem, hu⟩ have : x ∈ u := mem_of_mem_nhdsWithin (mem_insert x s) u_mem exact (hu x this).mono_of_mem_nhdsWithin (nhdsWithin_mono _ (subset_insert x s) u_mem) -protected theorem ContDiffWithinAt.eventually {n : ℕ} (h : ContDiffWithinAt 𝕜 n f s x) : +protected theorem ContDiffWithinAt.eventually (h : ContDiffWithinAt 𝕜 n f s x) (hn : n ≠ ∞) : ∀ᶠ y in 𝓝[insert x s] x, ContDiffWithinAt 𝕜 n f s y := by - rcases h.contDiffOn le_rfl with ⟨u, hu, _, hd⟩ + rcases h.contDiffOn le_rfl (by simp [hn]) with ⟨u, hu, _, hd⟩ have : ∀ᶠ y : E in 𝓝[insert x s] x, u ∈ 𝓝[insert x s] y ∧ y ∈ u := (eventually_eventually_nhdsWithin.2 hu).and hu refine this.mono fun y hy => (hd y hy.2).mono_of_mem_nhdsWithin ?_ exact nhdsWithin_mono y (subset_insert _ _) hy.1 -theorem ContDiffOn.of_le (h : ContDiffOn 𝕜 n f s) (hmn : m ≤ n) : ContDiffOn 𝕜 m f s := fun x hx => - (h x hx).of_le hmn - -theorem ContDiffOn.of_succ {n : ℕ} (h : ContDiffOn 𝕜 (n + 1) f s) : ContDiffOn 𝕜 n f s := - h.of_le <| WithTop.coe_le_coe.mpr le_self_add +theorem ContDiffOn.of_succ (h : ContDiffOn 𝕜 (n + 1) f s) : ContDiffOn 𝕜 n f s := + h.of_le le_self_add -theorem ContDiffOn.one_of_succ {n : ℕ} (h : ContDiffOn 𝕜 (n + 1) f s) : ContDiffOn 𝕜 1 f s := - h.of_le <| WithTop.coe_le_coe.mpr le_add_self +theorem ContDiffOn.one_of_succ (h : ContDiffOn 𝕜 (n + 1) f s) : ContDiffOn 𝕜 1 f s := + h.of_le le_add_self theorem contDiffOn_iff_forall_nat_le {n : ℕ∞} : ContDiffOn 𝕜 n f s ↔ ∀ m : ℕ, ↑m ≤ n → ContDiffOn 𝕜 m f s := - ⟨fun H _ hm => H.of_le (mod_cast hm), fun H x hx m hm => H m (mod_cast hm) x hx m le_rfl⟩ + ⟨fun H _ hm => H.of_le (mod_cast hm), fun H x hx m hm => H m hm x hx m le_rfl⟩ -theorem contDiffOn_top : ContDiffOn 𝕜 ∞ f s ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := +theorem contDiffOn_infty : ContDiffOn 𝕜 ∞ f s ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := contDiffOn_iff_forall_nat_le.trans <| by simp only [le_top, forall_prop_of_true] +@[deprecated (since := "2024-11-27")] alias contDiffOn_top := contDiffOn_infty +@[deprecated (since := "2024-11-27")] +alias contDiffOn_infty_iff_contDiffOn_omega := contDiffOn_infty + theorem contDiffOn_all_iff_nat : (∀ (n : ℕ∞), ContDiffOn 𝕜 n f s) ↔ ∀ n : ℕ, ContDiffOn 𝕜 n f s := by refine ⟨fun H n => H n, ?_⟩ rintro H (_ | n) - exacts [contDiffOn_top.2 H, H n] + exacts [contDiffOn_infty.2 H, H n] theorem ContDiffOn.continuousOn (h : ContDiffOn 𝕜 n f s) : ContinuousOn f s := fun x hx => (h x hx).continuousWithinAt @@ -478,28 +598,28 @@ theorem contDiffOn_of_locally_contDiffOn exact IsOpen.mem_nhds u_open xu /-- A function is `C^(n + 1)` on a domain iff locally, it has a derivative which is `C^n`. -/ -theorem contDiffOn_succ_iff_hasFDerivWithinAt {n : ℕ} : +theorem contDiffOn_succ_iff_hasFDerivWithinAt (hn : n ≠ ∞) : ContDiffOn 𝕜 (n + 1) f s ↔ - ∀ x ∈ s, ∃ u ∈ 𝓝[insert x s] x, ∃ f' : E → E →L[𝕜] F, + ∀ x ∈ s, ∃ u ∈ 𝓝[insert x s] x, (n = ω → AnalyticOn 𝕜 f u) ∧ ∃ f' : E → E →L[𝕜] F, (∀ x ∈ u, HasFDerivWithinAt f (f' x) u x) ∧ ContDiffOn 𝕜 n f' u := by constructor · intro h x hx - rcases (h x hx) n.succ le_rfl with ⟨u, hu, p, Hp⟩ - refine - ⟨u, hu, fun y => (continuousMultilinearCurryFin1 𝕜 E F) (p y 1), fun y hy => - Hp.hasFDerivWithinAt (mod_cast (Nat.le_add_left 1 n)) hy, ?_⟩ - rw [show (n.succ : WithTop ℕ∞) = (n : ℕ) + 1 from rfl, - hasFTaylorSeriesUpToOn_succ_iff_right] at Hp - intro z hz m hm - refine ⟨u, ?_, fun x : E => (p x).shift, Hp.2.2.of_le (mod_cast hm)⟩ - -- Porting note: without the explicit arguments `convert` can not determine the type. - convert @self_mem_nhdsWithin _ _ z u - exact insert_eq_of_mem hz + rcases (contDiffWithinAt_succ_iff_hasFDerivWithinAt hn).1 (h x hx) with + ⟨u, hu, f_an, f', hf', Hf'⟩ + rcases Hf'.contDiffOn le_rfl (by simp [hn]) with ⟨v, vu, v'u, hv⟩ + rw [insert_eq_of_mem hx] at hu ⊢ + have xu : x ∈ u := mem_of_mem_nhdsWithin hx hu + rw [insert_eq_of_mem xu] at vu v'u + exact ⟨v, nhdsWithin_le_of_mem hu vu, fun h ↦ (f_an h).mono v'u, f', + fun y hy ↦ (hf' y (v'u hy)).mono v'u, hv⟩ · intro h x hx - rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt] - rcases h x hx with ⟨u, u_nhbd, f', hu, hf'⟩ + rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt hn] + rcases h x hx with ⟨u, u_nhbd, f_an, f', hu, hf'⟩ have : x ∈ u := mem_of_mem_nhdsWithin (mem_insert _ _) u_nhbd - exact ⟨u, u_nhbd, f', hu, hf' x this⟩ + exact ⟨u, u_nhbd, f_an, f', hu, hf' x this⟩ + + +/-! ### Iterated derivative within a set -/ @[simp] theorem contDiffOn_zero : ContDiffOn 𝕜 0 f s ↔ ContinuousOn f s := by @@ -526,7 +646,8 @@ theorem contDiffWithinAt_zero (hx : x ∈ s) : /-- When a function is `C^n` in a set `s` of unique differentiability, it admits `ftaylorSeriesWithin 𝕜 f s` as a Taylor series up to order `n` in `s`. -/ -protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) : +protected theorem ContDiffOn.ftaylorSeriesWithin + (h : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) : HasFTaylorSeriesUpToOn n f (ftaylorSeriesWithin 𝕜 f s) s := by constructor · intro x _ @@ -556,7 +677,7 @@ protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs · intro m hm apply continuousOn_of_locally_continuousOn intro x hx - rcases h x hx m (mod_cast hm) with ⟨u, hu, p, Hp⟩ + rcases (h x hx).of_le hm _ le_rfl with ⟨u, hu, p, Hp⟩ rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ rw [insert_eq_of_mem hx] at ho rw [inter_comm] at ho @@ -568,6 +689,42 @@ protected theorem ContDiffOn.ftaylorSeriesWithin (h : ContDiffOn 𝕜 n f s) (hs exact (Hp.mono ho).eq_iteratedFDerivWithin_of_uniqueDiffOn le_rfl (hs.inter o_open) ⟨hy, yo⟩ exact ((Hp.mono ho).cont m le_rfl).congr fun y hy => (A y hy).symm +theorem iteratedFDerivWithin_subset {n : ℕ} (st : s ⊆ t) (hs : UniqueDiffOn 𝕜 s) + (ht : UniqueDiffOn 𝕜 t) (h : ContDiffOn 𝕜 n f t) (hx : x ∈ s) : + iteratedFDerivWithin 𝕜 n f s x = iteratedFDerivWithin 𝕜 n f t x := + (((h.ftaylorSeriesWithin ht).mono st).eq_iteratedFDerivWithin_of_uniqueDiffOn le_rfl hs hx).symm + +/-- On a set with unique differentiability, an analytic function is automatically `C^ω`, as its +successive derivatives are also analytic. This does not require completeness of the space. See +also `AnalyticOn.contDiffOn_of_completeSpace`.-/ +theorem AnalyticOn.contDiffOn (h : AnalyticOn 𝕜 f s) (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 n f s := by + suffices ContDiffOn 𝕜 ω f s from this.of_le le_top + rcases h.exists_hasFTaylorSeriesUpToOn hs with ⟨p, hp⟩ + intro x hx + refine ⟨s, ?_, p, hp⟩ + rw [insert_eq_of_mem hx] + exact self_mem_nhdsWithin + +@[deprecated (since := "2024-09-26")] +alias AnalyticWithinOn.contDiffOn := AnalyticOn.contDiffOn + +/-- On a set with unique differentiability, an analytic function is automatically `C^ω`, as its +successive derivatives are also analytic. This does not require completeness of the space. See +also `AnalyticOnNhd.contDiffOn_of_completeSpace`. -/ +theorem AnalyticOnNhd.contDiffOn (h : AnalyticOnNhd 𝕜 f s) (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 n f s := h.analyticOn.contDiffOn hs + +/-- An analytic function is automatically `C^ω` in a complete space -/ +theorem AnalyticOn.contDiffOn_of_completeSpace [CompleteSpace F] (h : AnalyticOn 𝕜 f s) : + ContDiffOn 𝕜 n f s := + fun x hx ↦ (h x hx).contDiffWithinAt + +/-- An analytic function is automatically `C^ω` in a complete space -/ +theorem AnalyticOnNhd.contDiffOn_of_completeSpace [CompleteSpace F] (h : AnalyticOnNhd 𝕜 f s) : + ContDiffOn 𝕜 n f s := + h.analyticOn.contDiffOn_of_completeSpace + theorem contDiffOn_of_continuousOn_differentiableOn {n : ℕ∞} (Hcont : ∀ m : ℕ, m ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) (Hdiff : ∀ m : ℕ, m < n → @@ -591,19 +748,47 @@ theorem contDiffOn_of_differentiableOn {n : ℕ∞} contDiffOn_of_continuousOn_differentiableOn (fun m hm => (h m hm).continuousOn) fun m hm => h m (le_of_lt hm) +theorem contDiffOn_of_analyticOn_iteratedFDerivWithin + (h : ∀ m, AnalyticOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s) : + ContDiffOn 𝕜 n f s := by + suffices ContDiffOn 𝕜 ω f s from this.of_le le_top + intro x hx + refine ⟨insert x s, self_mem_nhdsWithin, ftaylorSeriesWithin 𝕜 f s, ?_, ?_⟩ + · rw [insert_eq_of_mem hx] + constructor + · intro y _ + simp only [ftaylorSeriesWithin, ContinuousMultilinearMap.curry0_apply, + iteratedFDerivWithin_zero_apply] + · intro k _ y hy + exact ((h k).differentiableOn y hy).hasFDerivWithinAt + · intro k _ + exact (h k).continuousOn + · intro i + rw [insert_eq_of_mem hx] + exact h i + +theorem contDiffOn_omega_iff_analyticOn (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 ω f s ↔ AnalyticOn 𝕜 f s := + ⟨fun h m ↦ h.analyticOn m, fun h ↦ h.contDiffOn hs⟩ + theorem ContDiffOn.continuousOn_iteratedFDerivWithin {m : ℕ} (h : ContDiffOn 𝕜 n f s) (hmn : m ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedFDerivWithin 𝕜 m f s) s := - (h.ftaylorSeriesWithin hs).cont m (mod_cast hmn) + ((h.of_le hmn).ftaylorSeriesWithin hs).cont m le_rfl theorem ContDiffOn.differentiableOn_iteratedFDerivWithin {m : ℕ} (h : ContDiffOn 𝕜 n f s) (hmn : m < n) (hs : UniqueDiffOn 𝕜 s) : - DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s := fun x hx => - ((h.ftaylorSeriesWithin hs).fderivWithin m (mod_cast hmn) x hx).differentiableWithinAt + DifferentiableOn 𝕜 (iteratedFDerivWithin 𝕜 m f s) s := by + intro x hx + have : (m + 1 : ℕ) ≤ n := ENat.add_one_natCast_le_withTop_of_lt hmn + apply (((h.of_le this).ftaylorSeriesWithin hs).fderivWithin m ?_ x hx).differentiableWithinAt + exact_mod_cast lt_add_one m theorem ContDiffWithinAt.differentiableWithinAt_iteratedFDerivWithin {m : ℕ} (h : ContDiffWithinAt 𝕜 n f s x) (hmn : m < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : DifferentiableWithinAt 𝕜 (iteratedFDerivWithin 𝕜 m f s) s x := by - rcases h.contDiffOn' (ENat.add_one_natCast_le_withTop_of_lt hmn) with ⟨u, uo, xu, hu⟩ + have : (m + 1 : WithTop ℕ∞) ≠ ∞ := Ne.symm (ne_of_beq_false rfl) + rcases h.contDiffOn' (ENat.add_one_natCast_le_withTop_of_lt hmn) (by simp [this]) + with ⟨u, uo, xu, hu⟩ set t := insert x s ∩ u have A : t =ᶠ[𝓝[≠] x] s := by simp only [set_eventuallyEq_iff_inf_principal, ← nhdsWithin_inter'] @@ -622,127 +807,140 @@ theorem contDiffOn_iff_continuousOn_differentiableOn {n : ℕ∞} (hs : UniqueDi ContDiffOn 𝕜 n f s ↔ (∀ m : ℕ, m ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) ∧ ∀ m : ℕ, m < n → DifferentiableOn 𝕜 (fun x => iteratedFDerivWithin 𝕜 m f s x) s := - ⟨fun h => ⟨fun _m hm => h.continuousOn_iteratedFDerivWithin (mod_cast hm) hs, fun _m hm => - h.differentiableOn_iteratedFDerivWithin (mod_cast hm) hs⟩, + ⟨fun h => ⟨fun _m hm => h.continuousOn_iteratedFDerivWithin (mod_cast hm) hs, + fun _m hm => h.differentiableOn_iteratedFDerivWithin (mod_cast hm) hs⟩, fun h => contDiffOn_of_continuousOn_differentiableOn h.1 h.2⟩ -theorem contDiffOn_succ_of_fderivWithin {n : ℕ} (hf : DifferentiableOn 𝕜 f s) +theorem contDiffOn_nat_iff_continuousOn_differentiableOn {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 n f s ↔ + (∀ m : ℕ, m ≤ n → ContinuousOn (fun x => iteratedFDerivWithin 𝕜 m f s x) s) ∧ + ∀ m : ℕ, m < n → DifferentiableOn 𝕜 (fun x => iteratedFDerivWithin 𝕜 m f s x) s := by + rw [show n = ((n : ℕ∞) : WithTop ℕ∞) from rfl, contDiffOn_iff_continuousOn_differentiableOn hs] + simp + +theorem contDiffOn_succ_of_fderivWithin (hf : DifferentiableOn 𝕜 f s) + (h' : n = ω → AnalyticOn 𝕜 f s) (h : ContDiffOn 𝕜 n (fun y => fderivWithin 𝕜 f s y) s) : ContDiffOn 𝕜 (n + 1) f s := by - intro x hx - rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt, insert_eq_of_mem hx] - exact - ⟨s, self_mem_nhdsWithin, fderivWithin 𝕜 f s, fun y hy => (hf y hy).hasFDerivWithinAt, h x hx⟩ + rcases eq_or_ne n ∞ with rfl | hn + · rw [ENat.coe_top_add_one, contDiffOn_infty] + intro m x hx + apply ContDiffWithinAt.of_le _ (show (m : WithTop ℕ∞) ≤ m + 1 from le_self_add) + rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt (by simp), + insert_eq_of_mem hx] + exact ⟨s, self_mem_nhdsWithin, (by simp), fderivWithin 𝕜 f s, + fun y hy => (hf y hy).hasFDerivWithinAt, (h x hx).of_le (mod_cast le_top)⟩ + · intro x hx + rw [contDiffWithinAt_succ_iff_hasFDerivWithinAt hn, + insert_eq_of_mem hx] + exact ⟨s, self_mem_nhdsWithin, h', fderivWithin 𝕜 f s, + fun y hy => (hf y hy).hasFDerivWithinAt, h x hx⟩ + +theorem contDiffOn_of_analyticOn_of_fderivWithin (hf : AnalyticOn 𝕜 f s) + (h : ContDiffOn 𝕜 ω (fun y ↦ fderivWithin 𝕜 f s y) s) : ContDiffOn 𝕜 n f s := by + suffices ContDiffOn 𝕜 (ω + 1) f s from this.of_le le_top + exact contDiffOn_succ_of_fderivWithin hf.differentiableOn (fun _ ↦ hf) h /-- A function is `C^(n + 1)` on a domain with unique derivatives if and only if it is differentiable there, and its derivative (expressed with `fderivWithin`) is `C^n`. -/ -theorem contDiffOn_succ_iff_fderivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : - ContDiffOn 𝕜 (n + 1) f s ↔ - DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 n (fun y => fderivWithin 𝕜 f s y) s := by - refine ⟨fun H => ?_, fun h => contDiffOn_succ_of_fderivWithin h.1 h.2⟩ - refine ⟨H.differentiableOn le_add_self, fun x hx => ?_⟩ - rcases contDiffWithinAt_succ_iff_hasFDerivWithinAt.1 (H x hx) with ⟨u, hu, f', hff', hf'⟩ - rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ - rw [inter_comm, insert_eq_of_mem hx] at ho - have := hf'.mono ho - rw [contDiffWithinAt_inter' (mem_nhdsWithin_of_mem_nhds (IsOpen.mem_nhds o_open xo))] at this - apply this.congr_of_eventuallyEq_of_mem _ hx - have : o ∩ s ∈ 𝓝[s] x := mem_nhdsWithin.2 ⟨o, o_open, xo, Subset.refl _⟩ - rw [inter_comm] at this - refine Filter.eventuallyEq_of_mem this fun y hy => ?_ - have A : fderivWithin 𝕜 f (s ∩ o) y = f' y := - ((hff' y (ho hy)).mono ho).fderivWithin (hs.inter o_open y hy) - rwa [fderivWithin_inter (o_open.mem_nhds hy.2)] at A - -theorem contDiffOn_succ_iff_hasFDerivWithin {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : +theorem contDiffOn_succ_iff_fderivWithin (hs : UniqueDiffOn 𝕜 s) : ContDiffOn 𝕜 (n + 1) f s ↔ + DifferentiableOn 𝕜 f s ∧ (n = ω → AnalyticOn 𝕜 f s) ∧ + ContDiffOn 𝕜 n (fderivWithin 𝕜 f s) s := by + refine ⟨fun H => ?_, fun h => contDiffOn_succ_of_fderivWithin h.1 h.2.1 h.2.2⟩ + refine ⟨H.differentiableOn le_add_self, ?_, fun x hx => ?_⟩ + · rintro rfl + exact H.analyticOn + have A (m : ℕ) (hm : m ≤ n) : ContDiffWithinAt 𝕜 m (fun y => fderivWithin 𝕜 f s y) s x := by + rcases (contDiffWithinAt_succ_iff_hasFDerivWithinAt (n := m) (ne_of_beq_false rfl)).1 + (H.of_le (add_le_add_right hm 1) x hx) with ⟨u, hu, -, f', hff', hf'⟩ + rcases mem_nhdsWithin.1 hu with ⟨o, o_open, xo, ho⟩ + rw [inter_comm, insert_eq_of_mem hx] at ho + have := hf'.mono ho + rw [contDiffWithinAt_inter' (mem_nhdsWithin_of_mem_nhds (IsOpen.mem_nhds o_open xo))] at this + apply this.congr_of_eventuallyEq_of_mem _ hx + have : o ∩ s ∈ 𝓝[s] x := mem_nhdsWithin.2 ⟨o, o_open, xo, Subset.refl _⟩ + rw [inter_comm] at this + refine Filter.eventuallyEq_of_mem this fun y hy => ?_ + have A : fderivWithin 𝕜 f (s ∩ o) y = f' y := + ((hff' y (ho hy)).mono ho).fderivWithin (hs.inter o_open y hy) + rwa [fderivWithin_inter (o_open.mem_nhds hy.2)] at A + match n with + | ω => exact (H.analyticOn.fderivWithin hs).contDiffOn hs (n := ω) x hx + | ∞ => exact contDiffWithinAt_infty.2 (fun m ↦ A m (mod_cast le_top)) + | (n : ℕ) => exact A n le_rfl + +theorem contDiffOn_succ_iff_hasFDerivWithinAt_of_uniqueDiffOn (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 (n + 1) f s ↔ (n = ω → AnalyticOn 𝕜 f s) ∧ ∃ f' : E → E →L[𝕜] F, ContDiffOn 𝕜 n f' s ∧ ∀ x, x ∈ s → HasFDerivWithinAt f (f' x) s x := by rw [contDiffOn_succ_iff_fderivWithin hs] - refine ⟨fun h => ⟨fderivWithin 𝕜 f s, h.2, fun x hx => (h.1 x hx).hasFDerivWithinAt⟩, fun h => ?_⟩ + refine ⟨fun h => ⟨h.2.1, fderivWithin 𝕜 f s, h.2.2, + fun x hx => (h.1 x hx).hasFDerivWithinAt⟩, fun ⟨f_an, h⟩ => ?_⟩ rcases h with ⟨f', h1, h2⟩ - refine ⟨fun x hx => (h2 x hx).differentiableWithinAt, fun x hx => ?_⟩ + refine ⟨fun x hx => (h2 x hx).differentiableWithinAt, f_an, fun x hx => ?_⟩ exact (h1 x hx).congr_of_mem (fun y hy => (h2 y hy).fderivWithin (hs y hy)) hx +@[deprecated (since := "2024-11-27")] +alias contDiffOn_succ_iff_hasFDerivWithin := contDiffOn_succ_iff_hasFDerivWithinAt_of_uniqueDiffOn + +theorem contDiffOn_infty_iff_fderivWithin (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 ∞ f s ↔ DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 ∞ (fderivWithin 𝕜 f s) s := by + rw [show ∞ = ∞ + 1 from rfl, contDiffOn_succ_iff_fderivWithin hs] + simp + +@[deprecated (since := "2024-11-27")] +alias contDiffOn_top_iff_fderivWithin := contDiffOn_infty_iff_fderivWithin + /-- A function is `C^(n + 1)` on an open domain if and only if it is differentiable there, and its derivative (expressed with `fderiv`) is `C^n`. -/ -theorem contDiffOn_succ_iff_fderiv_of_isOpen {n : ℕ} (hs : IsOpen s) : +theorem contDiffOn_succ_iff_fderiv_of_isOpen (hs : IsOpen s) : ContDiffOn 𝕜 (n + 1) f s ↔ - DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 n (fun y => fderiv 𝕜 f y) s := by + DifferentiableOn 𝕜 f s ∧ (n = ω → AnalyticOn 𝕜 f s) ∧ + ContDiffOn 𝕜 n (fderiv 𝕜 f) s := by rw [contDiffOn_succ_iff_fderivWithin hs.uniqueDiffOn] - exact Iff.rfl.and (contDiffOn_congr fun x hx ↦ fderivWithin_of_isOpen hs hx) + exact Iff.rfl.and (Iff.rfl.and (contDiffOn_congr fun x hx ↦ fderivWithin_of_isOpen hs hx)) -/-- A function is `C^∞` on a domain with unique derivatives if and only if it is differentiable -there, and its derivative (expressed with `fderivWithin`) is `C^∞`. -/ -theorem contDiffOn_top_iff_fderivWithin (hs : UniqueDiffOn 𝕜 s) : - ContDiffOn 𝕜 ∞ f s ↔ - DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 ∞ (fun y => fderivWithin 𝕜 f s y) s := by - constructor - · intro h - refine ⟨h.differentiableOn (mod_cast le_top), ?_⟩ - refine contDiffOn_top.2 fun n => ((contDiffOn_succ_iff_fderivWithin hs).1 ?_).2 - exact h.of_le (mod_cast le_top) - · intro h - refine contDiffOn_top.2 fun n => ?_ - have A : (n : ℕ∞) ≤ ∞ := mod_cast le_top - apply ((contDiffOn_succ_iff_fderivWithin hs).2 ⟨h.1, h.2.of_le A⟩).of_le - exact_mod_cast (Nat.le_succ n) - -/-- A function is `C^∞` on an open domain if and only if it is differentiable there, and its -derivative (expressed with `fderiv`) is `C^∞`. -/ -theorem contDiffOn_top_iff_fderiv_of_isOpen (hs : IsOpen s) : - ContDiffOn 𝕜 ∞ f s ↔ DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 ∞ (fun y => fderiv 𝕜 f y) s := by - rw [contDiffOn_top_iff_fderivWithin hs.uniqueDiffOn] - exact Iff.rfl.and <| contDiffOn_congr fun x hx ↦ fderivWithin_of_isOpen hs hx +theorem contDiffOn_infty_iff_fderiv_of_isOpen (hs : IsOpen s) : + ContDiffOn 𝕜 ∞ f s ↔ DifferentiableOn 𝕜 f s ∧ ContDiffOn 𝕜 ∞ (fderiv 𝕜 f) s := by + rw [show ∞ = ∞ + 1 from rfl, contDiffOn_succ_iff_fderiv_of_isOpen hs] + simp + +@[deprecated (since := "2024-11-27")] +alias contDiffOn_top_iff_fderiv_of_isOpen := contDiffOn_infty_iff_fderiv_of_isOpen protected theorem ContDiffOn.fderivWithin (hf : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) - (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (fun y => fderivWithin 𝕜 f s y) s := by - rcases le_or_lt ∞ n with hn | hn - · have : ContDiffOn 𝕜 ∞ (fun y ↦ fderivWithin 𝕜 f s y) s := - ((contDiffOn_top_iff_fderivWithin hs).1 (hf.of_le hn)).2 - intro x hx k hk - exact this x hx k (mod_cast le_top) - · match m with - | ω => simpa using hmn.trans_lt hn - | ∞ => simpa using hmn.trans_lt hn - | (m : ℕ) => - change (m.succ : ℕ∞) ≤ n at hmn - exact ((contDiffOn_succ_iff_fderivWithin hs).1 (hf.of_le hmn)).2 + (hmn : m + 1 ≤ n) : ContDiffOn 𝕜 m (fderivWithin 𝕜 f s) s := + ((contDiffOn_succ_iff_fderivWithin hs).1 (hf.of_le hmn)).2.2 theorem ContDiffOn.fderiv_of_isOpen (hf : ContDiffOn 𝕜 n f s) (hs : IsOpen s) (hmn : m + 1 ≤ n) : - ContDiffOn 𝕜 m (fun y => fderiv 𝕜 f y) s := + ContDiffOn 𝕜 m (fderiv 𝕜 f) s := (hf.fderivWithin hs.uniqueDiffOn hmn).congr fun _ hx => (fderivWithin_of_isOpen hs hx).symm theorem ContDiffOn.continuousOn_fderivWithin (h : ContDiffOn 𝕜 n f s) (hs : UniqueDiffOn 𝕜 s) - (hn : 1 ≤ n) : ContinuousOn (fun x => fderivWithin 𝕜 f s x) s := - ((contDiffOn_succ_iff_fderivWithin hs).1 (h.of_le hn)).2.continuousOn + (hn : 1 ≤ n) : ContinuousOn (fderivWithin 𝕜 f s) s := + ((contDiffOn_succ_iff_fderivWithin hs).1 + (h.of_le (show 0 + (1 : WithTop ℕ∞) ≤ n from hn))).2.2.continuousOn theorem ContDiffOn.continuousOn_fderiv_of_isOpen (h : ContDiffOn 𝕜 n f s) (hs : IsOpen s) - (hn : 1 ≤ n) : ContinuousOn (fun x => fderiv 𝕜 f x) s := - ((contDiffOn_succ_iff_fderiv_of_isOpen hs).1 (h.of_le hn)).2.continuousOn - -/-- The following lemma will be removed when the definition of `C^ω` will be corrected. For now, -it is only there as a convenient shortcut. -/ -theorem contDiffOn_infty_iff_contDiffOn_omega : - ContDiffOn 𝕜 ∞ f s ↔ ContDiffOn 𝕜 ω f s := by - have A (m : ℕ) : m ≤ ∞ := mod_cast le_top - simp [ContDiffOn, ContDiffWithinAt, hasFTaylorSeriesUpTo_top_iff, A] + (hn : 1 ≤ n) : ContinuousOn (fderiv 𝕜 f) s := + ((contDiffOn_succ_iff_fderiv_of_isOpen hs).1 + (h.of_le (show 0 + (1 : WithTop ℕ∞) ≤ n from hn))).2.2.continuousOn /-! ### Smooth functions at a point -/ -variable (𝕜) - +variable (𝕜) in /-- A function is continuously differentiable up to `n` at a point `x` if, for any integer `k ≤ n`, there is a neighborhood of `x` where `f` admits derivatives up to order `n`, which are continuous. -/ def ContDiffAt (n : WithTop ℕ∞) (f : E → F) (x : E) : Prop := ContDiffWithinAt 𝕜 n f univ x -variable {𝕜} - theorem contDiffWithinAt_univ : ContDiffWithinAt 𝕜 n f univ x ↔ ContDiffAt 𝕜 n f x := Iff.rfl -theorem contDiffAt_top : ContDiffAt 𝕜 ∞ f x ↔ ∀ n : ℕ, ContDiffAt 𝕜 n f x := by - simp [← contDiffWithinAt_univ, contDiffWithinAt_top] +theorem contDiffAt_infty : ContDiffAt 𝕜 ∞ f x ↔ ∀ n : ℕ, ContDiffAt 𝕜 n f x := by + simp [← contDiffWithinAt_univ, contDiffWithinAt_infty] + +@[deprecated (since := "2024-11-27")] alias contDiffAt_top := contDiffAt_infty theorem ContDiffAt.contDiffWithinAt (h : ContDiffAt 𝕜 n f x) : ContDiffWithinAt 𝕜 n f s x := h.mono (subset_univ _) @@ -772,6 +970,20 @@ theorem ContDiffAt.of_le (h : ContDiffAt 𝕜 n f x) (hmn : m ≤ n) : ContDiffA theorem ContDiffAt.continuousAt (h : ContDiffAt 𝕜 n f x) : ContinuousAt f x := by simpa [continuousWithinAt_univ] using h.continuousWithinAt +theorem ContDiffAt.analyticAt (h : ContDiffAt 𝕜 ω f x) : AnalyticAt 𝕜 f x := by + rw [← contDiffWithinAt_univ] at h + rw [← analyticWithinAt_univ] + exact h.analyticWithinAt + +/-- In a complete space, a function which is analytic at a point is also `C^ω` there. +Note that the same statement for `AnalyticOn` does not require completeness, see +`AnalyticOn.contDiffOn`. -/ +theorem AnalyticAt.contDiffAt [CompleteSpace F] (h : AnalyticAt 𝕜 f x) : + ContDiffAt 𝕜 n f x := by + rw [← contDiffWithinAt_univ] + rw [← analyticWithinAt_univ] at h + exact h.contDiffWithinAt + @[simp] theorem contDiffWithinAt_compl_self : ContDiffWithinAt 𝕜 n f {x}ᶜ x ↔ ContDiffAt 𝕜 n f x := by @@ -782,18 +994,18 @@ theorem ContDiffAt.differentiableAt (h : ContDiffAt 𝕜 n f x) (hn : 1 ≤ n) : DifferentiableAt 𝕜 f x := by simpa [hn, differentiableWithinAt_univ] using h.differentiableWithinAt -nonrec lemma ContDiffAt.contDiffOn {m : ℕ} (h : ContDiffAt 𝕜 n f x) (hm : m ≤ n) : +nonrec lemma ContDiffAt.contDiffOn (h : ContDiffAt 𝕜 n f x) (hm : m ≤ n) (h' : m = ∞ → n = ω): ∃ u ∈ 𝓝 x, ContDiffOn 𝕜 m f u := by - simpa [nhdsWithin_univ] using h.contDiffOn hm + simpa [nhdsWithin_univ] using h.contDiffOn hm h' /-- A function is `C^(n + 1)` at a point iff locally, it has a derivative which is `C^n`. -/ theorem contDiffAt_succ_iff_hasFDerivAt {n : ℕ} : - ContDiffAt 𝕜 (n + 1) f x ↔ - ∃ f' : E → E →L[𝕜] F, (∃ u ∈ 𝓝 x, ∀ x ∈ u, HasFDerivAt f (f' x) x) ∧ ContDiffAt 𝕜 n f' x := by - rw [← contDiffWithinAt_univ, contDiffWithinAt_succ_iff_hasFDerivWithinAt] + ContDiffAt 𝕜 (n + 1) f x ↔ ∃ f' : E → E →L[𝕜] F, + (∃ u ∈ 𝓝 x, ∀ x ∈ u, HasFDerivAt f (f' x) x) ∧ ContDiffAt 𝕜 n f' x := by + rw [← contDiffWithinAt_univ, contDiffWithinAt_succ_iff_hasFDerivWithinAt (by simp)] simp only [nhdsWithin_univ, exists_prop, mem_univ, insert_eq_of_mem] constructor - · rintro ⟨u, H, f', h_fderiv, h_cont_diff⟩ + · rintro ⟨u, H, -, f', h_fderiv, h_cont_diff⟩ rcases mem_nhds_iff.mp H with ⟨t, htu, ht, hxt⟩ refine ⟨f', ⟨t, ?_⟩, h_cont_diff.contDiffAt H⟩ refine ⟨mem_nhds_iff.mpr ⟨t, Subset.rfl, ht, hxt⟩, ?_⟩ @@ -801,41 +1013,67 @@ theorem contDiffAt_succ_iff_hasFDerivAt {n : ℕ} : refine (h_fderiv y (htu hyt)).hasFDerivAt ?_ exact mem_nhds_iff.mpr ⟨t, htu, ht, hyt⟩ · rintro ⟨f', ⟨u, H, h_fderiv⟩, h_cont_diff⟩ - refine ⟨u, H, f', ?_, h_cont_diff.contDiffWithinAt⟩ - intro x hxu + refine ⟨u, H, by simp, f', fun x hxu ↦ ?_, h_cont_diff.contDiffWithinAt⟩ exact (h_fderiv x hxu).hasFDerivWithinAt -protected theorem ContDiffAt.eventually {n : ℕ} (h : ContDiffAt 𝕜 n f x) : +protected theorem ContDiffAt.eventually (h : ContDiffAt 𝕜 n f x) (h' : n ≠ ∞) : ∀ᶠ y in 𝓝 x, ContDiffAt 𝕜 n f y := by - simpa [nhdsWithin_univ] using ContDiffWithinAt.eventually h + simpa [nhdsWithin_univ] using ContDiffWithinAt.eventually h h' + +theorem iteratedFDerivWithin_eq_iteratedFDeriv {n : ℕ} + (hs : UniqueDiffOn 𝕜 s) (h : ContDiffAt 𝕜 n f x) (hx : x ∈ s) : + iteratedFDerivWithin 𝕜 n f s x = iteratedFDeriv 𝕜 n f x := by + rw [← iteratedFDerivWithin_univ] + rcases h.contDiffOn' le_rfl (by simp) with ⟨u, u_open, xu, hu⟩ + rw [← iteratedFDerivWithin_inter_open u_open xu, + ← iteratedFDerivWithin_inter_open u_open xu (s := univ)] + apply iteratedFDerivWithin_subset + · exact inter_subset_inter_left _ (subset_univ _) + · exact hs.inter u_open + · apply uniqueDiffOn_univ.inter u_open + · simpa using hu + · exact ⟨hx, xu⟩ /-! ### Smooth functions -/ -variable (𝕜) - +variable (𝕜) in /-- A function is continuously differentiable up to `n` if it admits derivatives up to order `n`, which are continuous. Contrary to the case of definitions in domains (where derivatives might not be unique) we do not need to localize the definition in space or time. -/ def ContDiff (n : WithTop ℕ∞) (f : E → F) : Prop := - ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpTo n f p - -variable {𝕜} + match n with + | ω => ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpTo ⊤ f p + ∧ ∀ i, AnalyticOnNhd 𝕜 (fun x ↦ p x i) univ + | (n : ℕ∞) => ∃ p : E → FormalMultilinearSeries 𝕜 E F, HasFTaylorSeriesUpTo n f p /-- If `f` has a Taylor series up to `n`, then it is `C^n`. -/ -theorem HasFTaylorSeriesUpTo.contDiff {f' : E → FormalMultilinearSeries 𝕜 E F} +theorem HasFTaylorSeriesUpTo.contDiff {n : ℕ∞} {f' : E → FormalMultilinearSeries 𝕜 E F} (hf : HasFTaylorSeriesUpTo n f f') : ContDiff 𝕜 n f := ⟨f', hf⟩ theorem contDiffOn_univ : ContDiffOn 𝕜 n f univ ↔ ContDiff 𝕜 n f := by - constructor - · intro H - use ftaylorSeriesWithin 𝕜 f univ - rw [← hasFTaylorSeriesUpToOn_univ_iff] - exact H.ftaylorSeriesWithin uniqueDiffOn_univ - · rintro ⟨p, hp⟩ x _ m hm - exact ⟨univ, Filter.univ_sets _, p, (hp.hasFTaylorSeriesUpToOn univ).of_le - (mod_cast hm)⟩ + match n with + | ω => + constructor + · intro H + use ftaylorSeriesWithin 𝕜 f univ + rw [← hasFTaylorSeriesUpToOn_univ_iff] + refine ⟨H.ftaylorSeriesWithin uniqueDiffOn_univ, fun i ↦ ?_⟩ + rw [← analyticOn_univ] + exact H.analyticOn.iteratedFDerivWithin uniqueDiffOn_univ _ + · rintro ⟨p, hp, h'p⟩ x _ + exact ⟨univ, Filter.univ_sets _, p, (hp.hasFTaylorSeriesUpToOn univ).of_le le_top, + fun i ↦ (h'p i).analyticOn⟩ + | (n : ℕ∞) => + constructor + · intro H + use ftaylorSeriesWithin 𝕜 f univ + rw [← hasFTaylorSeriesUpToOn_univ_iff] + exact H.ftaylorSeriesWithin uniqueDiffOn_univ + · rintro ⟨p, hp⟩ x _ m hm + exact ⟨univ, Filter.univ_sets _, p, + (hp.hasFTaylorSeriesUpToOn univ).of_le (mod_cast hm)⟩ theorem contDiff_iff_contDiffAt : ContDiff 𝕜 n f ↔ ∀ x, ContDiffAt 𝕜 n f x := by simp [← contDiffOn_univ, ContDiffOn, ContDiffAt] @@ -846,16 +1084,14 @@ theorem ContDiff.contDiffAt (h : ContDiff 𝕜 n f) : ContDiffAt 𝕜 n f x := theorem ContDiff.contDiffWithinAt (h : ContDiff 𝕜 n f) : ContDiffWithinAt 𝕜 n f s x := h.contDiffAt.contDiffWithinAt -/-- The following lemma will be removed when the definition of `C^ω` will be corrected. For now, -it is only there as a convenient shortcut. -/ -theorem contDiff_infty_iff_contDiff_omega : - ContDiff 𝕜 ∞ f ↔ ContDiff 𝕜 ω f := by - simp [ContDiff, hasFTaylorSeriesUpTo_top_iff] +theorem contDiff_infty : ContDiff 𝕜 ∞ f ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by + simp [contDiffOn_univ.symm, contDiffOn_infty] + +@[deprecated (since := "2024-11-25")] alias contDiff_top := contDiff_infty -theorem contDiff_top : ContDiff 𝕜 ∞ f ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by - simp [contDiffOn_univ.symm, contDiffOn_top] +@[deprecated (since := "2024-11-25")] alias contDiff_infty_iff_contDiff_omega := contDiff_infty -theorem contDiff_all_iff_nat : (∀ (n : ℕ∞), ContDiff 𝕜 n f) ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by +theorem contDiff_all_iff_nat : (∀ n : ℕ∞, ContDiff 𝕜 n f) ↔ ∀ n : ℕ, ContDiff 𝕜 n f := by simp only [← contDiffOn_univ, contDiffOn_all_iff_nat] theorem ContDiff.contDiffOn (h : ContDiff 𝕜 n f) : ContDiffOn 𝕜 n f s := @@ -872,18 +1108,18 @@ theorem contDiffAt_zero : ContDiffAt 𝕜 0 f x ↔ ∃ u ∈ 𝓝 x, Continuous theorem contDiffAt_one_iff : ContDiffAt 𝕜 1 f x ↔ ∃ f' : E → E →L[𝕜] F, ∃ u ∈ 𝓝 x, ContinuousOn f' u ∧ ∀ x ∈ u, HasFDerivAt f (f' x) x := by - rw [show (1 : WithTop ℕ∞) = (0 : ℕ) + 1 from rfl, contDiffAt_succ_iff_hasFDerivAt] - simp_rw [show ((0 : ℕ) : WithTop ℕ∞) = 0 from rfl, contDiffAt_zero, - exists_mem_and_iff antitone_bforall antitone_continuousOn, and_comm] + rw [show (1 : WithTop ℕ∞) = (0 : ℕ) + 1 from rfl] + simp_rw [contDiffAt_succ_iff_hasFDerivAt, show ((0 : ℕ) : WithTop ℕ∞) = 0 from rfl, + contDiffAt_zero, exists_mem_and_iff antitone_bforall antitone_continuousOn, and_comm] theorem ContDiff.of_le (h : ContDiff 𝕜 n f) (hmn : m ≤ n) : ContDiff 𝕜 m f := contDiffOn_univ.1 <| (contDiffOn_univ.2 h).of_le hmn -theorem ContDiff.of_succ {n : ℕ} (h : ContDiff 𝕜 (n + 1) f) : ContDiff 𝕜 n f := - h.of_le <| WithTop.coe_le_coe.mpr le_self_add +theorem ContDiff.of_succ (h : ContDiff 𝕜 (n + 1) f) : ContDiff 𝕜 n f := + h.of_le le_self_add -theorem ContDiff.one_of_succ {n : ℕ} (h : ContDiff 𝕜 (n + 1) f) : ContDiff 𝕜 1 f := - h.of_le <| WithTop.coe_le_coe.mpr le_add_self +theorem ContDiff.one_of_succ (h : ContDiff 𝕜 (n + 1) f) : ContDiff 𝕜 1 f := by + apply h.of_le le_add_self theorem ContDiff.continuous (h : ContDiff 𝕜 n f) : Continuous f := contDiff_zero.1 (h.of_le bot_le) @@ -900,21 +1136,49 @@ theorem contDiff_iff_forall_nat_le {n : ℕ∞} : theorem contDiff_succ_iff_hasFDerivAt {n : ℕ} : ContDiff 𝕜 (n + 1) f ↔ ∃ f' : E → E →L[𝕜] F, ContDiff 𝕜 n f' ∧ ∀ x, HasFDerivAt f (f' x) x := by - simp only [← contDiffOn_univ, ← hasFDerivWithinAt_univ, - contDiffOn_succ_iff_hasFDerivWithin uniqueDiffOn_univ, Set.mem_univ, forall_true_left] + simp only [← contDiffOn_univ, ← hasFDerivWithinAt_univ, Set.mem_univ, forall_true_left, + contDiffOn_succ_iff_hasFDerivWithinAt_of_uniqueDiffOn uniqueDiffOn_univ, + WithTop.natCast_ne_top, analyticOn_univ, false_implies, true_and] theorem contDiff_one_iff_hasFDerivAt : ContDiff 𝕜 1 f ↔ ∃ f' : E → E →L[𝕜] F, Continuous f' ∧ ∀ x, HasFDerivAt f (f' x) x := by convert contDiff_succ_iff_hasFDerivAt using 4; simp -/-- When a function is `C^n` in a set `s` of unique differentiability, it admits -`ftaylorSeriesWithin 𝕜 f s` as a Taylor series up to order `n` in `s`. -/ -theorem contDiff_iff_ftaylorSeries : +theorem AnalyticOn.contDiff (hf : AnalyticOn 𝕜 f univ) : ContDiff 𝕜 n f := by + rw [← contDiffOn_univ] + exact hf.contDiffOn (n := n) uniqueDiffOn_univ + +theorem AnalyticOnNhd.contDiff (hf : AnalyticOnNhd 𝕜 f univ) : ContDiff 𝕜 n f := + hf.analyticOn.contDiff + +theorem ContDiff.analyticOnNhd (h : ContDiff 𝕜 ω f) : AnalyticOnNhd 𝕜 f s := by + rw [← contDiffOn_univ] at h + have := h.analyticOn + rw [analyticOn_univ] at this + exact this.mono (subset_univ _) + +theorem contDiff_omega_iff_analyticOnNhd : + ContDiff 𝕜 ω f ↔ AnalyticOnNhd 𝕜 f univ := + ⟨fun h ↦ h.analyticOnNhd, fun h ↦ h.contDiff⟩ + +/-! ### Iterated derivative -/ + +/-- When a function is `C^n`, it admits `ftaylorSeries 𝕜 f` as a Taylor series up +to order `n` in `s`. -/ +theorem ContDiff.ftaylorSeries (hf : ContDiff 𝕜 n f) : + HasFTaylorSeriesUpTo n f (ftaylorSeries 𝕜 f) := by + simp only [← contDiffOn_univ, ← hasFTaylorSeriesUpToOn_univ_iff, ← ftaylorSeriesWithin_univ] + at hf ⊢ + exact ContDiffOn.ftaylorSeriesWithin hf uniqueDiffOn_univ + +/-- For `n : ℕ∞`, a function is `C^n` iff it admits `ftaylorSeries 𝕜 f` +as a Taylor series up to order `n`. -/ +theorem contDiff_iff_ftaylorSeries {n : ℕ∞} : ContDiff 𝕜 n f ↔ HasFTaylorSeriesUpTo n f (ftaylorSeries 𝕜 f) := by constructor · rw [← contDiffOn_univ, ← hasFTaylorSeriesUpToOn_univ_iff, ← ftaylorSeriesWithin_univ] - exact fun h => ContDiffOn.ftaylorSeriesWithin h uniqueDiffOn_univ - · intro h; exact ⟨ftaylorSeries 𝕜 f, h⟩ + exact fun h ↦ ContDiffOn.ftaylorSeriesWithin h uniqueDiffOn_univ + · exact fun h ↦ ⟨ftaylorSeries 𝕜 f, h⟩ theorem contDiff_iff_continuous_differentiable {n : ℕ∞} : ContDiff 𝕜 n f ↔ @@ -923,6 +1187,13 @@ theorem contDiff_iff_continuous_differentiable {n : ℕ∞} : simp [contDiffOn_univ.symm, continuous_iff_continuousOn_univ, differentiableOn_univ.symm, iteratedFDerivWithin_univ, contDiffOn_iff_continuousOn_differentiableOn uniqueDiffOn_univ] +theorem contDiff_nat_iff_continuous_differentiable {n : ℕ} : + ContDiff 𝕜 n f ↔ + (∀ m : ℕ, m ≤ n → Continuous fun x => iteratedFDeriv 𝕜 m f x) ∧ + ∀ m : ℕ, m < n → Differentiable 𝕜 fun x => iteratedFDeriv 𝕜 m f x := by + rw [show n = ((n : ℕ∞) : WithTop ℕ∞) from rfl, contDiff_iff_continuous_differentiable] + simp + /-- If `f` is `C^n` then its `m`-times iterated derivative is continuous for `m ≤ n`. -/ theorem ContDiff.continuous_iteratedFDeriv {m : ℕ} (hm : m ≤ n) (hf : ContDiff 𝕜 n f) : Continuous fun x => iteratedFDeriv 𝕜 m f x := @@ -941,24 +1212,27 @@ theorem contDiff_of_differentiable_iteratedFDeriv {n : ℕ∞} /-- A function is `C^(n + 1)` if and only if it is differentiable, and its derivative (formulated in terms of `fderiv`) is `C^n`. -/ -theorem contDiff_succ_iff_fderiv {n : ℕ} : - ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ ContDiff 𝕜 n fun y => fderiv 𝕜 f y := by +theorem contDiff_succ_iff_fderiv : + ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ (n = ω → AnalyticOnNhd 𝕜 f univ) ∧ + ContDiff 𝕜 n (fderiv 𝕜 f) := by simp only [← contDiffOn_univ, ← differentiableOn_univ, ← fderivWithin_univ, - contDiffOn_succ_iff_fderivWithin uniqueDiffOn_univ] + contDiffOn_succ_iff_fderivWithin uniqueDiffOn_univ, analyticOn_univ] + +theorem contDiff_one_iff_fderiv : + ContDiff 𝕜 1 f ↔ Differentiable 𝕜 f ∧ Continuous (fderiv 𝕜 f) := by + rw [show (1 : WithTop ℕ∞) = 0 + 1 from rfl, contDiff_succ_iff_fderiv] + simp -theorem contDiff_one_iff_fderiv : ContDiff 𝕜 1 f ↔ Differentiable 𝕜 f ∧ Continuous (fderiv 𝕜 f) := - contDiff_succ_iff_fderiv.trans <| Iff.rfl.and contDiff_zero +theorem contDiff_infty_iff_fderiv : + ContDiff 𝕜 ∞ f ↔ Differentiable 𝕜 f ∧ ContDiff 𝕜 ∞ (fderiv 𝕜 f) := by + rw [show ∞ = ∞ + 1 from rfl, contDiff_succ_iff_fderiv] + simp -/-- A function is `C^∞` if and only if it is differentiable, -and its derivative (formulated in terms of `fderiv`) is `C^∞`. -/ -theorem contDiff_top_iff_fderiv : - ContDiff 𝕜 ∞ f ↔ Differentiable 𝕜 f ∧ ContDiff 𝕜 ∞ fun y => fderiv 𝕜 f y := by - simp only [← contDiffOn_univ, ← differentiableOn_univ, ← fderivWithin_univ] - rw [contDiffOn_top_iff_fderivWithin uniqueDiffOn_univ] +@[deprecated (since := "2024-11-27")] alias contDiff_top_iff_fderiv := contDiff_infty_iff_fderiv theorem ContDiff.continuous_fderiv (h : ContDiff 𝕜 n f) (hn : 1 ≤ n) : - Continuous fun x => fderiv 𝕜 f x := - (contDiff_succ_iff_fderiv.1 (h.of_le hn)).2.continuous + Continuous (fderiv 𝕜 f) := + (contDiff_one_iff_fderiv.1 (h.of_le hn)).2 /-- If a function is at least `C^1`, its bundled derivative (mapping `(x, v)` to `Df(x) v`) is continuous. -/ diff --git a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean index abdac0002a6e2..45f5ee0897fc4 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FTaylorSeries.lean @@ -3,6 +3,7 @@ Copyright (c) 2019 Sébastien Gouëzel. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ +import Mathlib.Analysis.Calculus.FDeriv.Add import Mathlib.Analysis.Calculus.FDeriv.Equiv import Mathlib.Analysis.Calculus.FormalMultilinearSeries @@ -98,10 +99,7 @@ In this file, we denote `⊤ : ℕ∞` with `∞`. noncomputable section -open scoped Classical -open ENat NNReal Topology Filter - -local notation "∞" => (⊤ : ℕ∞) +open ENat NNReal Topology Filter Set Fin Filter Function /- Porting note: These lines are not required in Mathlib4. @@ -109,7 +107,12 @@ attribute [local instance 1001] NormedAddCommGroup.toAddCommGroup NormedSpace.toModule' AddCommGroup.toAddCommMonoid -/ -open Set Fin Filter Function +/-- Smoothness exponent for analytic functions. -/ +scoped [ContDiff] notation3 "ω" => (⊤ : WithTop ℕ∞) +/-- Smoothness exponent for infinitely differentiable functions. -/ +scoped [ContDiff] notation3 "∞" => ((⊤ : ℕ∞) : WithTop ℕ∞) + +open scoped ContDiff Pointwise universe u uE uF @@ -129,7 +132,7 @@ Notice that `p` does not sum up to `f` on the diagonal (`FormalMultilinearSeries structure HasFTaylorSeriesUpToOn (n : WithTop ℕ∞) (f : E → F) (p : E → FormalMultilinearSeries 𝕜 E F) (s : Set E) : Prop where zero_eq : ∀ x ∈ s, (p x 0).curry0 = f x - protected fderivWithin : ∀ m : ℕ, (m : ℕ∞) < n → ∀ x ∈ s, + protected fderivWithin : ∀ m : ℕ, m < n → ∀ x ∈ s, HasFDerivWithinAt (p · m) (p x m.succ).curryLeft s x cont : ∀ m : ℕ, m ≤ n → ContinuousOn (p · m) s @@ -146,6 +149,16 @@ theorem HasFTaylorSeriesUpToOn.congr (h : HasFTaylorSeriesUpToOn n f p s) rw [h₁ x hx] exact h.zero_eq x hx +theorem HasFTaylorSeriesUpToOn.congr_series {q} (hp : HasFTaylorSeriesUpToOn n f p s) + (hpq : ∀ m : ℕ, m ≤ n → EqOn (p · m) (q · m) s) : + HasFTaylorSeriesUpToOn n f q s where + zero_eq x hx := by simp only [← (hpq 0 (zero_le n) hx), hp.zero_eq x hx] + fderivWithin m hm x hx := by + refine ((hp.fderivWithin m hm x hx).congr' (hpq m hm.le).symm hx).congr_fderiv ?_ + refine congrArg _ (hpq (m + 1) ?_ hx) + exact ENat.add_one_natCast_le_withTop_of_lt hm + cont m hm := (hp.cont m hm).congr (hpq m hm).symm + theorem HasFTaylorSeriesUpToOn.mono (h : HasFTaylorSeriesUpToOn n f p s) {t : Set E} (hst : t ⊆ s) : HasFTaylorSeriesUpToOn n f p t := ⟨fun x hx => h.zero_eq x (hst hx), fun m hm x hx => (h.fderivWithin m hm x (hst hx)).mono hst, @@ -502,6 +515,13 @@ lemma iteratedFDerivWithin_two_apply (f : E → F) {z : E} (hs : UniqueDiffOn simp only [iteratedFDerivWithin_succ_apply_right hs hz] rfl +/-- On a set of unique differentiability, the second derivative is obtained by taking the +derivative of the derivative. -/ +lemma iteratedFDerivWithin_two_apply' (f : E → F) {z : E} (hs : UniqueDiffOn 𝕜 s) (hz : z ∈ s) + (v w : E) : + iteratedFDerivWithin 𝕜 2 f s z ![v, w] = fderivWithin 𝕜 (fderivWithin 𝕜 f s) s z v w := + iteratedFDerivWithin_two_apply f hs hz _ + theorem Filter.EventuallyEq.iteratedFDerivWithin' (h : f₁ =ᶠ[𝓝[s] x] f) (ht : t ⊆ s) (n : ℕ) : iteratedFDerivWithin 𝕜 n f₁ t =ᶠ[𝓝[s] x] iteratedFDerivWithin 𝕜 n f t := by induction n with @@ -549,10 +569,31 @@ theorem iteratedFDerivWithin_eventually_congr_set (h : s =ᶠ[𝓝 x] t) (n : iteratedFDerivWithin 𝕜 n f s =ᶠ[𝓝 x] iteratedFDerivWithin 𝕜 n f t := iteratedFDerivWithin_eventually_congr_set' x (h.filter_mono inf_le_left) n +/-- If two sets coincide in a punctured neighborhood of `x`, +then the corresponding iterated derivatives are equal. + +Note that we also allow to puncture the neighborhood of `x` at `y`. +If `y ≠ x`, then this is a no-op. -/ +theorem iteratedFDerivWithin_congr_set' {y} (h : s =ᶠ[𝓝[{y}ᶜ] x] t) (n : ℕ) : + iteratedFDerivWithin 𝕜 n f s x = iteratedFDerivWithin 𝕜 n f t x := + (iteratedFDerivWithin_eventually_congr_set' y h n).self_of_nhds + +@[simp] +theorem iteratedFDerivWithin_insert {n y} : + iteratedFDerivWithin 𝕜 n f (insert x s) y = iteratedFDerivWithin 𝕜 n f s y := + iteratedFDerivWithin_congr_set' (y := x) + (eventually_mem_nhdsWithin.mono <| by intros; simp_all).set_eq _ + theorem iteratedFDerivWithin_congr_set (h : s =ᶠ[𝓝 x] t) (n : ℕ) : iteratedFDerivWithin 𝕜 n f s x = iteratedFDerivWithin 𝕜 n f t x := (iteratedFDerivWithin_eventually_congr_set h n).self_of_nhds +@[simp] +theorem ftaylorSeriesWithin_insert : + ftaylorSeriesWithin 𝕜 f (insert x s) = ftaylorSeriesWithin 𝕜 f s := by + ext y n : 2 + apply iteratedFDerivWithin_insert + /-- The iterated differential within a set `s` at a point `x` is not modified if one intersects `s` with a neighborhood of `x` within `s`. -/ theorem iteratedFDerivWithin_inter' {n : ℕ} (hu : u ∈ 𝓝[s] x) : @@ -578,7 +619,7 @@ theorem HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn (hx : x ∈ s) : p x m = iteratedFDerivWithin 𝕜 m f s x := by induction' m with m IH generalizing x · rw [h.zero_eq' hx, iteratedFDerivWithin_zero_eq_comp]; rfl - · have A : (m : ℕ∞) < n := lt_of_lt_of_le (mod_cast lt_add_one m) hmn + · have A : m < n := lt_of_lt_of_le (mod_cast lt_add_one m) hmn have : HasFDerivWithinAt (fun y : E => iteratedFDerivWithin 𝕜 m f s y) (ContinuousMultilinearMap.curryLeft (p x (Nat.succ m))) s x := @@ -591,6 +632,48 @@ theorem HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn alias HasFTaylorSeriesUpToOn.eq_ftaylor_series_of_uniqueDiffOn := HasFTaylorSeriesUpToOn.eq_iteratedFDerivWithin_of_uniqueDiffOn +/-- The iterated derivative commutes with shifting the function by a constant on the left. -/ +lemma iteratedFDerivWithin_comp_add_left' (n : ℕ) (a : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (a + z)) s = + fun x ↦ iteratedFDerivWithin 𝕜 n f (a +ᵥ s) (a + x) := by + induction n with + | zero => simp [iteratedFDerivWithin] + | succ n IH => + ext v + rw [iteratedFDerivWithin_succ_eq_comp_left, iteratedFDerivWithin_succ_eq_comp_left] + simp only [Nat.succ_eq_add_one, IH, comp_apply, continuousMultilinearCurryLeftEquiv_symm_apply] + congr 2 + rw [fderivWithin_comp_add_left] + +/-- The iterated derivative commutes with shifting the function by a constant on the left. -/ +lemma iteratedFDerivWithin_comp_add_left (n : ℕ) (a : E) (x : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (a + z)) s x = + iteratedFDerivWithin 𝕜 n f (a +ᵥ s) (a + x) := by + simp [iteratedFDerivWithin_comp_add_left'] + +/-- The iterated derivative commutes with shifting the function by a constant on the right. -/ +lemma iteratedFDerivWithin_comp_add_right' (n : ℕ) (a : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (z + a)) s = + fun x ↦ iteratedFDerivWithin 𝕜 n f (a +ᵥ s) (x + a) := by + simpa [add_comm a] using iteratedFDerivWithin_comp_add_left' n a + +/-- The iterated derivative commutes with shifting the function by a constant on the right. -/ +lemma iteratedFDerivWithin_comp_add_right (n : ℕ) (a : E) (x : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (z + a)) s x = + iteratedFDerivWithin 𝕜 n f (a +ᵥ s) (x + a) := by + simp [iteratedFDerivWithin_comp_add_right'] + +/-- The iterated derivative commutes with subtracting a constant. -/ +lemma iteratedFDerivWithin_comp_sub' (n : ℕ) (a : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (z - a)) s = + fun x ↦ iteratedFDerivWithin 𝕜 n f (-a +ᵥ s) (x - a) := by + simpa [sub_eq_add_neg] using iteratedFDerivWithin_comp_add_right' n (-a) + +/-- The iterated derivative commutes with subtracting a constant. -/ +lemma iteratedFDerivWithin_comp_sub (n : ℕ) (a : E) : + iteratedFDerivWithin 𝕜 n (fun z ↦ f (z - a)) s x = + iteratedFDerivWithin 𝕜 n f (-a +ᵥ s) (x - a) := by + simp [iteratedFDerivWithin_comp_sub'] /-! ### Functions with a Taylor series on the whole space -/ @@ -776,7 +859,7 @@ theorem iteratedFDerivWithin_univ {n : ℕ} : rw [iteratedFDeriv_succ_apply_left, iteratedFDerivWithin_succ_apply_left, IH, fderivWithin_univ] theorem HasFTaylorSeriesUpTo.eq_iteratedFDeriv - (h : HasFTaylorSeriesUpTo n f p) {m : ℕ} (hmn : (m : ℕ∞) ≤ n) (x : E) : + (h : HasFTaylorSeriesUpTo n f p) {m : ℕ} (hmn : m ≤ n) (x : E) : p x m = iteratedFDeriv 𝕜 m f x := by rw [← iteratedFDerivWithin_univ] rw [← hasFTaylorSeriesUpToOn_univ_iff] at h @@ -834,3 +917,33 @@ lemma iteratedFDeriv_two_apply (f : E → F) (z : E) (m : Fin 2 → E) : iteratedFDeriv 𝕜 2 f z m = fderiv 𝕜 (fderiv 𝕜 f) z (m 0) (m 1) := by simp only [iteratedFDeriv_succ_apply_right] rfl + +/-- The iterated derivative commutes with shifting the function by a constant on the left. -/ +lemma iteratedFDeriv_comp_add_left' (n : ℕ) (a : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (a + z)) = fun x ↦ iteratedFDeriv 𝕜 n f (a + x) := by + simpa [← iteratedFDerivWithin_univ] using iteratedFDerivWithin_comp_add_left' n a (s := univ) + +/-- The iterated derivative commutes with shifting the function by a constant on the left. -/ +lemma iteratedFDeriv_comp_add_left (n : ℕ) (a : E) (x : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (a + z)) x = iteratedFDeriv 𝕜 n f (a + x) := by + simp [iteratedFDeriv_comp_add_left'] + +/-- The iterated derivative commutes with shifting the function by a constant on the right. -/ +lemma iteratedFDeriv_comp_add_right' (n : ℕ) (a : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (z + a)) = fun x ↦ iteratedFDeriv 𝕜 n f (x + a) := by + simpa [add_comm a] using iteratedFDeriv_comp_add_left' n a + +/-- The iterated derivative commutes with shifting the function by a constant on the right. -/ +lemma iteratedFDeriv_comp_add_right (n : ℕ) (a : E) (x : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (z + a)) x = iteratedFDeriv 𝕜 n f (x + a) := by + simp [iteratedFDeriv_comp_add_right'] + +/-- The iterated derivative commutes with subtracting a constant. -/ +lemma iteratedFDeriv_comp_sub' (n : ℕ) (a : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (z - a)) = fun x ↦ iteratedFDeriv 𝕜 n f (x - a) := by + simpa [sub_eq_add_neg] using iteratedFDeriv_comp_add_right' n (-a) + +/-- The iterated derivative commutes with subtracting a constant. -/ +lemma iteratedFDeriv_comp_sub (n : ℕ) (a : E) (x : E) : + iteratedFDeriv 𝕜 n (fun z ↦ f (z - a)) x = iteratedFDeriv 𝕜 n f (x - a) := by + simp [iteratedFDeriv_comp_sub'] diff --git a/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean b/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean index 2138cf98fdb9d..f8b0483d56f73 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FaaDiBruno.lean @@ -207,7 +207,7 @@ noncomputable def equivSigma : ((i : Fin c.length) × Fin (c.partSize i)) ≃ Fi lemma length_pos (h : 0 < n) : 0 < c.length := Nat.zero_lt_of_lt (c.index ⟨0, h⟩).2 lemma neZero_length [NeZero n] (c : OrderedFinpartition n) : NeZero c.length := - ⟨(c.length_pos size_pos').ne'⟩ + ⟨(c.length_pos pos').ne'⟩ lemma neZero_partSize (c : OrderedFinpartition n) (i : Fin c.length) : NeZero (c.partSize i) := .of_pos (c.partSize_pos i) @@ -953,7 +953,7 @@ theorem HasFTaylorSeriesUpToOn.comp {n : WithTop ℕ∞} {g : F → G} {f : E hf.hasFDerivWithinAt (le_trans (mod_cast Nat.le_add_left 1 m) (ENat.add_one_natCast_le_withTop_of_lt hm)) hx convert HasFDerivWithinAt.linear_multilinear_comp (J.comp x K h) I B - simp only [Nat.succ_eq_add_one, Fintype.sum_option, comp_apply, faaDiBruno_aux1, + simp only [B, Nat.succ_eq_add_one, Fintype.sum_option, comp_apply, faaDiBruno_aux1, faaDiBruno_aux2] have B : HasFDerivWithinAt (fun x ↦ (q (f x)).taylorComp (p x) m) (∑ c : OrderedFinpartition m, ∑ i : Option (Fin c.length), diff --git a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean index c399175ddd00d..a403a0f90c9d8 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/FiniteDimension.lean @@ -28,8 +28,11 @@ section FiniteDimensional open Function Module +open scoped ContDiff + variable [CompleteSpace 𝕜] + /-- A family of continuous linear maps is `C^n` on `s` if all its applications are. -/ theorem contDiffOn_clm_apply {f : D → E →L[𝕜] F} {s : Set D} [FiniteDimensional 𝕜 E] : ContDiffOn 𝕜 n f s ↔ ∀ y, ContDiffOn 𝕜 n (fun x => f x y) s := by @@ -53,20 +56,22 @@ domain and codomain (`D` and `E`). This is not the case for `contDiff_succ_iff_f often requires an inconvenient need to generalize `F`, which results in universe issues (see the discussion in the section of `ContDiff.comp`). -This lemma avoids these universe issues, but only applies for finite dimensional `E`. -/ -theorem contDiff_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} : - ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ ∀ y, ContDiff 𝕜 n fun x => fderiv 𝕜 f x y := by +This lemma avoids these universe issues, but only applies for finite dimensional `D`. -/ +theorem contDiff_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] : + ContDiff 𝕜 (n + 1) f ↔ Differentiable 𝕜 f ∧ + (n = ω → AnalyticOnNhd 𝕜 f Set.univ) ∧ ∀ y, ContDiff 𝕜 n fun x => fderiv 𝕜 f x y := by rw [contDiff_succ_iff_fderiv, contDiff_clm_apply_iff] -theorem contDiffOn_succ_of_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} {s : Set D} - (hf : DifferentiableOn 𝕜 f s) (h : ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s) : +theorem contDiffOn_succ_of_fderiv_apply [FiniteDimensional 𝕜 D] + (hf : DifferentiableOn 𝕜 f s) (h'f : n = ω → AnalyticOn 𝕜 f s) + (h : ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s) : ContDiffOn 𝕜 (n + 1) f s := - contDiffOn_succ_of_fderivWithin hf <| contDiffOn_clm_apply.mpr h + contDiffOn_succ_of_fderivWithin hf h'f <| contDiffOn_clm_apply.mpr h -theorem contDiffOn_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] {n : ℕ} {f : D → E} {s : Set D} - (hs : UniqueDiffOn 𝕜 s) : +theorem contDiffOn_succ_iff_fderiv_apply [FiniteDimensional 𝕜 D] (hs : UniqueDiffOn 𝕜 s) : ContDiffOn 𝕜 (n + 1) f s ↔ - DifferentiableOn 𝕜 f s ∧ ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s := by + DifferentiableOn 𝕜 f s ∧ (n = ω → AnalyticOn 𝕜 f s) ∧ + ∀ y, ContDiffOn 𝕜 n (fun x => fderivWithin 𝕜 f s x y) s := by rw [contDiffOn_succ_iff_fderivWithin hs, contDiffOn_clm_apply] end FiniteDimensional diff --git a/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean b/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean index 4c99b51e455ba..7c1f15c0a1dd3 100644 --- a/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean +++ b/Mathlib/Analysis/Calculus/ContDiff/WithLp.lean @@ -17,24 +17,24 @@ open ContinuousLinearMap variable {𝕜 ι : Type*} {E : ι → Type*} {H : Type*} variable [NontriviallyNormedField 𝕜] [NormedAddCommGroup H] [∀ i, NormedAddCommGroup (E i)] [∀ i, NormedSpace 𝕜 (E i)] [NormedSpace 𝕜 H] [Fintype ι] (p) [Fact (1 ≤ p)] - {f : H → PiLp p E} {f' : H →L[𝕜] PiLp p E} {t : Set H} {y : H} + {n : WithTop ℕ∞} {f : H → PiLp p E} {f' : H →L[𝕜] PiLp p E} {t : Set H} {y : H} -theorem contDiffWithinAt_piLp {n : ℕ∞} : +theorem contDiffWithinAt_piLp : ContDiffWithinAt 𝕜 n f t y ↔ ∀ i, ContDiffWithinAt 𝕜 n (fun x => f x i) t y := by rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_contDiffWithinAt_iff, contDiffWithinAt_pi] rfl -theorem contDiffAt_piLp {n : ℕ∞} : +theorem contDiffAt_piLp : ContDiffAt 𝕜 n f y ↔ ∀ i, ContDiffAt 𝕜 n (fun x => f x i) y := by rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_contDiffAt_iff, contDiffAt_pi] rfl -theorem contDiffOn_piLp {n : ℕ∞} : +theorem contDiffOn_piLp : ContDiffOn 𝕜 n f t ↔ ∀ i, ContDiffOn 𝕜 n (fun x => f x i) t := by rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_contDiffOn_iff, contDiffOn_pi] rfl -theorem contDiff_piLp {n : ℕ∞} : ContDiff 𝕜 n f ↔ ∀ i, ContDiff 𝕜 n fun x => f x i := by +theorem contDiff_piLp : ContDiff 𝕜 n f ↔ ∀ i, ContDiff 𝕜 n fun x => f x i := by rw [← (PiLp.continuousLinearEquiv p 𝕜 E).comp_contDiff_iff, contDiff_pi] rfl diff --git a/Mathlib/Analysis/Calculus/FDeriv/Add.lean b/Mathlib/Analysis/Calculus/FDeriv/Add.lean index e513cd4e78b50..e6fb07b97cd41 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Add.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Add.lean @@ -711,4 +711,122 @@ theorem fderiv_const_sub (c : F) : fderiv 𝕜 (fun y => c - f y) x = -fderiv end Sub +section CompAdd + +/-! ### Derivative of the composition with a translation -/ + +open scoped Pointwise Topology + +theorem hasFDerivWithinAt_comp_add_right (a : E) : + HasFDerivWithinAt (fun x ↦ f (x + a)) f' s x ↔ HasFDerivWithinAt f f' (a +ᵥ s) (x + a) := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · have A : f = (fun x ↦ f (x + a)) ∘ (fun x ↦ x - a) := by ext; simp + rw [show x = (x + a) - a by abel] at h + rw [A] + have : HasFDerivWithinAt (fun x ↦ x - a) (ContinuousLinearMap.id 𝕜 E) (a +ᵥ s) (x + a) := by + simpa using (hasFDerivWithinAt_id (x + a) _).sub (hasFDerivWithinAt_const _ _ _) + apply h.comp (x + a) this (fun y hy ↦ ?_) + simpa [Set.mem_vadd_set_iff_neg_vadd_mem, add_comm, ← sub_eq_add_neg] using hy + · have : HasFDerivWithinAt (fun x ↦ x + a) (ContinuousLinearMap.id 𝕜 E) s x := by + simpa using (hasFDerivWithinAt_id x s (𝕜 := 𝕜)).add (hasFDerivWithinAt_const a x s (𝕜 := 𝕜)) + apply h.comp x this (fun y hy ↦ ?_) + simp [Set.mem_vadd_set_iff_neg_vadd_mem, hy] + +theorem differentiableWithinAt_comp_add_right (a : E) : + DifferentiableWithinAt 𝕜 (fun x ↦ f (x + a)) s x ↔ + DifferentiableWithinAt 𝕜 f (a +ᵥ s) (x + a) := by + simp [DifferentiableWithinAt, hasFDerivWithinAt_comp_add_right] + +theorem fderivWithin_comp_add_right (a : E) : + fderivWithin 𝕜 (fun x ↦ f (x + a)) s x = fderivWithin 𝕜 f (a +ᵥ s) (x + a) := by + simp only [fderivWithin, hasFDerivWithinAt_comp_add_right] + by_cases h : 𝓝[s \ {x}] x = ⊥ + · have h' : 𝓝[(a +ᵥ s) \ {x + a}] (x + a) = ⊥ := by + let e := Homeomorph.addRight a + have : 𝓝[(a +ᵥ s) \ {x + a}] (x + a) = map e (𝓝[s \ {x}] x) := by + rw [e.isEmbedding.map_nhdsWithin_eq] + congr + ext y + rw [← e.preimage_symm] + simp [e, Homeomorph.addRight, Set.mem_vadd_set_iff_neg_vadd_mem, add_comm] + rw [this, h, Filter.map_bot] + simp [h, h'] + · have h' : 𝓝[(a +ᵥ s) \ {x + a}] (x + a) ≠ ⊥ := by + intro h'' + let e := Homeomorph.addRight (-a) + have : 𝓝[s \ {x}] x = map e (𝓝[(a +ᵥ s) \ {x + a}] (x + a)) := by + rw [e.isEmbedding.map_nhdsWithin_eq] + congr + · simp [e] + ext y + rw [← e.preimage_symm] + simp [e, Homeomorph.addRight, Set.mem_vadd_set_iff_neg_vadd_mem, add_comm] + apply h + rw [this, h'', Filter.map_bot] + simp [h, h'] + +theorem hasFDerivWithinAt_comp_add_left (a : E) : + HasFDerivWithinAt (fun x ↦ f (a + x)) f' s x ↔ HasFDerivWithinAt f f' (a +ᵥ s) (a + x) := by + simpa [add_comm a] using hasFDerivWithinAt_comp_add_right a + +theorem differentiableWithinAt_comp_add_left (a : E) : + DifferentiableWithinAt 𝕜 (fun x ↦ f (a + x)) s x ↔ + DifferentiableWithinAt 𝕜 f (a +ᵥ s) (a + x) := by + simp [DifferentiableWithinAt, hasFDerivWithinAt_comp_add_left] + +theorem fderivWithin_comp_add_left (a : E) : + fderivWithin 𝕜 (fun x ↦ f (a + x)) s x = fderivWithin 𝕜 f (a +ᵥ s) (a + x) := by + simpa [add_comm a] using fderivWithin_comp_add_right a + +theorem hasFDerivAt_comp_add_right (a : E) : + HasFDerivAt (fun x ↦ f (x + a)) f' x ↔ HasFDerivAt f f' (x + a) := by + simp [← hasFDerivWithinAt_univ, hasFDerivWithinAt_comp_add_right] + +theorem differentiableAt_comp_add_right (a : E) : + DifferentiableAt 𝕜 (fun x ↦ f (x + a)) x ↔ DifferentiableAt 𝕜 f (x + a) := by + simp [DifferentiableAt, hasFDerivAt_comp_add_right] + +theorem fderiv_comp_add_right (a : E) : + fderiv 𝕜 (fun x ↦ f (x + a)) x = fderiv 𝕜 f (x + a) := by + simp [← fderivWithin_univ, fderivWithin_comp_add_right] + +theorem hasFDerivAt_comp_add_left (a : E) : + HasFDerivAt (fun x ↦ f (a + x)) f' x ↔ HasFDerivAt f f' (a + x) := by + simpa [add_comm a] using hasFDerivAt_comp_add_right a + +theorem differentiableAt_comp_add_left (a : E) : + DifferentiableAt 𝕜 (fun x ↦ f (a + x)) x ↔ DifferentiableAt 𝕜 f (a + x) := by + simp [DifferentiableAt, hasFDerivAt_comp_add_left] + +theorem fderiv_comp_add_left (a : E) : + fderiv 𝕜 (fun x ↦ f (a + x)) x = fderiv 𝕜 f (a + x) := by + simpa [add_comm a] using fderiv_comp_add_right a + +theorem hasFDerivWithinAt_comp_sub (a : E) : + HasFDerivWithinAt (fun x ↦ f (x - a)) f' s x ↔ HasFDerivWithinAt f f' (-a +ᵥ s) (x - a) := by + simpa [sub_eq_add_neg] using hasFDerivWithinAt_comp_add_right (-a) + +theorem differentiableWithinAt_comp_sub (a : E) : + DifferentiableWithinAt 𝕜 (fun x ↦ f (x - a)) s x ↔ + DifferentiableWithinAt 𝕜 f (-a +ᵥ s) (x - a) := by + simp [DifferentiableWithinAt, hasFDerivWithinAt_comp_sub] + +theorem fderivWithin_comp_sub (a : E) : + fderivWithin 𝕜 (fun x ↦ f (x - a)) s x = fderivWithin 𝕜 f (-a +ᵥ s) (x - a) := by + simpa [sub_eq_add_neg] using fderivWithin_comp_add_right (-a) + +theorem hasFDerivAt_comp_sub (a : E) : + HasFDerivAt (fun x ↦ f (x - a)) f' x ↔ HasFDerivAt f f' (x - a) := by + simp [← hasFDerivWithinAt_univ, hasFDerivWithinAt_comp_sub] + +theorem differentiableAt_comp_sub (a : E) : + DifferentiableAt 𝕜 (fun x ↦ f (x - a)) x ↔ DifferentiableAt 𝕜 f (x - a) := by + simp [DifferentiableAt, hasFDerivAt_comp_sub] + +theorem fderiv_comp_sub (a : E) : + fderiv 𝕜 (fun x ↦ f (x - a)) x = fderiv 𝕜 f (x - a) := by + simp [← fderivWithin_univ, fderivWithin_comp_sub] + +end CompAdd + end diff --git a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean index 48cb70ce773fd..fb89da18adf7c 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Analytic.lean @@ -222,6 +222,17 @@ protected theorem HasFPowerSeriesWithinOnBall.fderivWithin [CompleteSpace F] · simpa only [edist_eq_coe_nnnorm_sub, EMetric.mem_ball] using hz.2 · simpa using hz.1 +/-- If a function has a power series within a set on a ball, then so does its derivative. For a +version without completeness, but assuming that the function is analytic on the set `s`, see +`HasFPowerSeriesWithinOnBall.fderivWithin_of_mem_of_analyticOn`. -/ +protected theorem HasFPowerSeriesWithinOnBall.fderivWithin_of_mem [CompleteSpace F] + (h : HasFPowerSeriesWithinOnBall f p s x r) (hu : UniqueDiffOn 𝕜 s) (hx : x ∈ s) : + HasFPowerSeriesWithinOnBall (fderivWithin 𝕜 f s) p.derivSeries s x r := by + have : insert x s = s := insert_eq_of_mem hx + rw [← this] at hu + convert h.fderivWithin hu + exact this.symm + /-- If a function is analytic on a set `s`, so is its Fréchet derivative. -/ protected theorem AnalyticAt.fderiv [CompleteSpace F] (h : AnalyticAt 𝕜 f x) : AnalyticAt 𝕜 (fderiv 𝕜 f) x := by @@ -255,7 +266,7 @@ protected theorem AnalyticOnNhd.iteratedFDeriv [CompleteSpace F] (h : AnalyticOn simp @[deprecated (since := "2024-09-26")] -alias AnalyticOn.iteratedFDeriv := AnalyticOnNhd.iteratedFDeriv +protected alias AnalyticOn.iteratedFDeriv := AnalyticOnNhd.iteratedFDeriv /-- If a function is analytic on a neighborhood of a set `s`, then it has a Taylor series given by the sequence of its derivatives. Note that, if the function were just analytic on `s`, then @@ -318,13 +329,13 @@ theorem HasFPowerSeriesWithinOnBall.hasSum_derivSeries_of_hasFDerivWithinAt Matrix.zero_empty] rfl -/-- If a function is analytic within a set with unique differentials, then so is its derivative. -Note that this theorem does not require completeness of the space. -/ -protected theorem AnalyticOn.fderivWithin (h : AnalyticOn 𝕜 f s) (hu : UniqueDiffOn 𝕜 s) : - AnalyticOn 𝕜 (fderivWithin 𝕜 f s) s := by - intro x hx - rcases h x hx with ⟨p, r, hr⟩ - refine ⟨p.derivSeries, r, ?_⟩ +/-- If a function has a power series within a set on a ball, then so does its derivative. Version +assuming that the function is analytic on `s`. For a version without this assumption but requiring +that `F` is complete, see `HasFPowerSeriesWithinOnBall.fderivWithin_of_mem`. -/ +protected theorem HasFPowerSeriesWithinOnBall.fderivWithin_of_mem_of_analyticOn + (hr : HasFPowerSeriesWithinOnBall f p s x r) + (h : AnalyticOn 𝕜 f s) (hs : UniqueDiffOn 𝕜 s) (hx : x ∈ s) : + HasFPowerSeriesWithinOnBall (fderivWithin 𝕜 f s) p.derivSeries s x r := by refine ⟨hr.r_le.trans p.radius_le_radius_derivSeries, hr.r_pos, fun {y} hy h'y ↦ ?_⟩ apply hr.hasSum_derivSeries_of_hasFDerivWithinAt (by simpa [edist_eq_coe_nnnorm] using h'y) hy · rw [insert_eq_of_mem hx] at hy ⊢ @@ -332,6 +343,14 @@ protected theorem AnalyticOn.fderivWithin (h : AnalyticOn 𝕜 f s) (hu : Unique exact h.differentiableOn _ hy · rwa [insert_eq_of_mem hx] +/-- If a function is analytic within a set with unique differentials, then so is its derivative. +Note that this theorem does not require completeness of the space. -/ +protected theorem AnalyticOn.fderivWithin (h : AnalyticOn 𝕜 f s) (hu : UniqueDiffOn 𝕜 s) : + AnalyticOn 𝕜 (fderivWithin 𝕜 f s) s := by + intro x hx + rcases h x hx with ⟨p, r, hr⟩ + refine ⟨p.derivSeries, r, hr.fderivWithin_of_mem_of_analyticOn h hu hx⟩ + /-- If a function is analytic on a set `s`, so are its successive Fréchet derivative within this set. Note that this theorem does not require completeness of the space. -/ protected theorem AnalyticOn.iteratedFDerivWithin (h : AnalyticOn 𝕜 f s) @@ -743,6 +762,10 @@ private theorem factorial_smul' {n : ℕ} : ∀ {F : Type max u v} [NormedAddCom variable [CompleteSpace F] include h +/-- The iterated derivative of an analytic function, on vectors `(y, ..., y)`, is given by `n!` +times the `n`-th term in the power series. For a more general result giving the full iterated +derivative as a sum over the permutations of `Fin n`, see +`HasFPowerSeriesOnBall.iteratedFDeriv_eq_sum`. -/ theorem factorial_smul (n : ℕ) : n ! • p n (fun _ ↦ y) = iteratedFDeriv 𝕜 n f x (fun _ ↦ y) := by cases n diff --git a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean index b396b208a0061..c381a83392646 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Basic.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Basic.lean @@ -70,7 +70,7 @@ example (x : ℝ) (h : 1 + sin x ≠ 0) : DifferentiableAt ℝ (fun x ↦ exp x simp [h] ``` Of course, these examples only work once `exp`, `cos` and `sin` have been shown to be -differentiable, in `Analysis.SpecialFunctions.Trigonometric`. +differentiable, in `Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv`. The simplifier is not set up to compute the Fréchet derivative of maps (as these are in general complicated multidimensional linear maps), but it will compute one-dimensional derivatives, diff --git a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean index c4db82a10c282..67c304e3952ff 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Bilinear.lean @@ -61,7 +61,7 @@ theorem IsBoundedBilinearMap.hasStrictFDerivAt (h : IsBoundedBilinearMap 𝕜 b) refine (isBigO_refl _ _).mul_isLittleO ((isLittleO_one_iff _).2 ?_) -- TODO: `continuity` fails exact (continuous_snd.fst.prod_mk continuous_fst.snd).norm.tendsto' _ _ (by simp) - _ = _ := by simp [Function.comp_def] + _ = _ := by simp [T, Function.comp_def] @[fun_prop] theorem IsBoundedBilinearMap.hasFDerivAt (h : IsBoundedBilinearMap 𝕜 b) (p : E × F) : diff --git a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean index e8073446374b3..3bc95aa8d8223 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Mul.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Mul.lean @@ -678,7 +678,7 @@ theorem HasFDerivAt.list_prod' {l : List ι} {x : E} smulRight (f' l[i]) ((l.drop (.succ i)).map (f · x)).prod) x := by simp only [← List.finRange_map_get l, List.map_map] refine .congr_fderiv (hasFDerivAt_list_prod_finRange'.comp x - (hasFDerivAt_pi.mpr fun i ↦ h l[i] (List.getElem_mem i.isLt))) ?_ + (hasFDerivAt_pi.mpr fun i ↦ h l[i] (l.getElem_mem _))) ?_ ext m simp [← List.map_map] @@ -690,7 +690,7 @@ theorem HasFDerivWithinAt.list_prod' {l : List ι} {x : E} smulRight (f' l[i]) ((l.drop (.succ i)).map (f · x)).prod) s x := by simp only [← List.finRange_map_get l, List.map_map] refine .congr_fderiv (hasFDerivAt_list_prod_finRange'.comp_hasFDerivWithinAt x - (hasFDerivWithinAt_pi.mpr fun i ↦ h l[i] (l.get_mem i i.isLt))) ?_ + (hasFDerivWithinAt_pi.mpr fun i ↦ h l[i] (l.getElem_mem _))) ?_ ext m simp [← List.map_map] diff --git a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean index b4f9b4db76e68..ad88a9cc37573 100644 --- a/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean +++ b/Mathlib/Analysis/Calculus/FDeriv/Symmetric.lean @@ -95,7 +95,7 @@ lemma fderivWithin_fderivWithin_eq_of_mem_nhdsWithin (h : t ∈ 𝓝[s] x) fderivWithin 𝕜 (fderivWithin 𝕜 f s) s x = fderivWithin 𝕜 (fderivWithin 𝕜 f t) t x := by have A : ∀ᶠ y in 𝓝[s] x, fderivWithin 𝕜 f s y = fderivWithin 𝕜 f t y := by have : ∀ᶠ y in 𝓝[s] x, ContDiffWithinAt 𝕜 2 f t y := - nhdsWithin_le_iff.2 h (nhdsWithin_mono _ (subset_insert x t) hf.eventually) + nhdsWithin_le_iff.2 h (nhdsWithin_mono _ (subset_insert x t) (hf.eventually (by simp))) filter_upwards [self_mem_nhdsWithin, this, eventually_eventually_nhdsWithin.2 h] with y hy h'y h''y exact fderivWithin_of_mem_nhdsWithin h''y (hs y hy) (h'y.differentiableWithinAt one_le_two) @@ -412,11 +412,13 @@ variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] [IsRCLikeNormedField 𝕜 [NormedSpace 𝕜 F] {s : Set E} {f : E → F} {x : E} theorem second_derivative_symmetric_of_eventually {f' : E → E →L[𝕜] F} {x : E} - {f'' : E →L[𝕜] E →L[𝕜] F} (hf : ∀ᶠ y in 𝓝 x, HasFDerivAt f (f' y) y) (hx : HasFDerivAt f' f'' x) - (v w : E) : f'' v w = f'' w v := by - letI := IsRCLikeNormedField.rclike 𝕜 - letI : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 E - letI : NormedSpace ℝ F := NormedSpace.restrictScalars ℝ 𝕜 F + {f'' : E →L[𝕜] E →L[𝕜] F} (hf : ∀ᶠ y in 𝓝 x, HasFDerivAt f (f' y) y) + (hx : HasFDerivAt f' f'' x) (v w : E) : f'' v w = f'' w v := by + let _ := IsRCLikeNormedField.rclike 𝕜 + let _ : NormedSpace ℝ E := NormedSpace.restrictScalars ℝ 𝕜 E + let _ : NormedSpace ℝ F := NormedSpace.restrictScalars ℝ 𝕜 F + let _ : LinearMap.CompatibleSMul E F ℝ 𝕜 := LinearMap.IsScalarTower.compatibleSMul + let _ : LinearMap.CompatibleSMul E (E →L[𝕜] F) ℝ 𝕜 := LinearMap.IsScalarTower.compatibleSMul let f'R : E → E →L[ℝ] F := fun x ↦ (f' x).restrictScalars ℝ have hfR : ∀ᶠ y in 𝓝 x, HasFDerivAt f (f'R y) y := by filter_upwards [hf] with y hy using HasFDerivAt.restrictScalars ℝ hy @@ -448,7 +450,8 @@ theorem ContDiffAt.isSymmSndFDerivAt {n : WithTop ℕ∞} (hf : ContDiffAt 𝕜 IsSymmSndFDerivAt 𝕜 f x := by intro v w apply second_derivative_symmetric_of_eventually (f := f) (f' := fderiv 𝕜 f) (x := x) - · obtain ⟨u, hu, h'u⟩ : ∃ u ∈ 𝓝 x, ContDiffOn 𝕜 2 f u := hf.contDiffOn (m := 2) hn + · obtain ⟨u, hu, h'u⟩ : ∃ u ∈ 𝓝 x, ContDiffOn 𝕜 2 f u := + (hf.of_le hn).contDiffOn (m := 2) le_rfl (by simp) rcases mem_nhds_iff.1 hu with ⟨v, vu, v_open, xv⟩ filter_upwards [v_open.mem_nhds xv] with y hy have : DifferentiableAt 𝕜 f y := by @@ -468,7 +471,7 @@ theorem ContDiffWithinAt.isSymmSndFDerivWithinAt {n : WithTop ℕ∞} (hf : Cont /- We argue that, at interior points, the second derivative is symmetric, and moreover by continuity it converges to the second derivative at `x`. Therefore, the latter is also symmetric. -/ - rcases hf.contDiffOn' hn with ⟨u, u_open, xu, hu⟩ + rcases (hf.of_le hn).contDiffOn' le_rfl (by simp) with ⟨u, u_open, xu, hu⟩ simp only [insert_eq_of_mem h'x] at hu have h'u : UniqueDiffOn 𝕜 (s ∩ u) := hs.inter u_open obtain ⟨y, hy, y_lim⟩ : ∃ y, (∀ (n : ℕ), y n ∈ interior s) ∧ Tendsto y atTop (𝓝 x) := diff --git a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean index 2dfe679519c45..d95f0f210244f 100644 --- a/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean +++ b/Mathlib/Analysis/Calculus/FormalMultilinearSeries.lean @@ -75,6 +75,12 @@ theorem zero_apply (n : ℕ) : (0 : FormalMultilinearSeries 𝕜 E F) n = 0 := r @[simp] theorem neg_apply (f : FormalMultilinearSeries 𝕜 E F) (n : ℕ) : (-f) n = - f n := rfl +@[simp] +theorem add_apply (p q : FormalMultilinearSeries 𝕜 E F) (n : ℕ) : (p + q) n = p n + q n := rfl + +@[simp] +theorem sub_apply (p q : FormalMultilinearSeries 𝕜 E F) (n : ℕ) : (p - q) n = p n - q n := rfl + @[ext] protected theorem ext {p q : FormalMultilinearSeries 𝕜 E F} (h : ∀ n, p n = q n) : p = q := funext h @@ -125,6 +131,10 @@ theorem congr (p : FormalMultilinearSeries 𝕜 E F) {m n : ℕ} {v : Fin m → congr with ⟨i, hi⟩ exact h2 i hi hi +lemma congr_zero (p : FormalMultilinearSeries 𝕜 E F) {k l : ℕ} (h : k = l) (h' : p k = 0) : + p l = 0 := by + subst h; exact h' + /-- Composing each term `pₙ` in a formal multilinear series with `(u, ..., u)` where `u` is a fixed continuous linear map, gives a new formal multilinear series `p.compContinuousLinearMap u`. -/ def compContinuousLinearMap (p : FormalMultilinearSeries 𝕜 F G) (u : E →L[𝕜] F) : diff --git a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean index 858642c83caa8..a013a881fc12f 100644 --- a/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean +++ b/Mathlib/Analysis/Calculus/IteratedDeriv/Defs.lean @@ -133,12 +133,12 @@ theorem contDiffOn_of_differentiableOn_deriv {n : ℕ∞} continuous. -/ theorem ContDiffOn.continuousOn_iteratedDerivWithin {n : WithTop ℕ∞} {m : ℕ} (h : ContDiffOn 𝕜 n f s) - (hmn : (m : ℕ∞) ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedDerivWithin m f s) s := by + (hmn : m ≤ n) (hs : UniqueDiffOn 𝕜 s) : ContinuousOn (iteratedDerivWithin m f s) s := by simpa only [iteratedDerivWithin_eq_equiv_comp, LinearIsometryEquiv.comp_continuousOn_iff] using h.continuousOn_iteratedFDerivWithin hmn hs theorem ContDiffWithinAt.differentiableWithinAt_iteratedDerivWithin {n : WithTop ℕ∞} {m : ℕ} - (h : ContDiffWithinAt 𝕜 n f s x) (hmn : (m : ℕ∞) < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : + (h : ContDiffWithinAt 𝕜 n f s x) (hmn : m < n) (hs : UniqueDiffOn 𝕜 (insert x s)) : DifferentiableWithinAt 𝕜 (iteratedDerivWithin m f s) s x := by simpa only [iteratedDerivWithin_eq_equiv_comp, LinearIsometryEquiv.comp_differentiableWithinAt_iff] using @@ -159,6 +159,15 @@ theorem contDiffOn_iff_continuousOn_differentiableOn_deriv {n : ℕ∞} (hs : Un simp only [contDiffOn_iff_continuousOn_differentiableOn hs, iteratedFDerivWithin_eq_equiv_comp, LinearIsometryEquiv.comp_continuousOn_iff, LinearIsometryEquiv.comp_differentiableOn_iff] +/-- The property of being `C^n`, initially defined in terms of the Fréchet derivative, can be +reformulated in terms of the one-dimensional derivative on sets with unique derivatives. -/ +theorem contDiffOn_nat_iff_continuousOn_differentiableOn_deriv {n : ℕ} (hs : UniqueDiffOn 𝕜 s) : + ContDiffOn 𝕜 n f s ↔ (∀ m : ℕ, m ≤ n → ContinuousOn (iteratedDerivWithin m f s) s) ∧ + ∀ m : ℕ, m < n → DifferentiableOn 𝕜 (iteratedDerivWithin m f s) s := by + rw [show n = ((n : ℕ∞) : WithTop ℕ∞) from rfl, + contDiffOn_iff_continuousOn_differentiableOn_deriv hs] + simp + /-- The `n+1`-th iterated derivative within a set with unique derivatives can be obtained by differentiating the `n`-th iterated derivative. -/ theorem iteratedDerivWithin_succ {x : 𝕜} (hxs : UniqueDiffWithinAt 𝕜 s x) : @@ -230,6 +239,14 @@ theorem contDiff_iff_iteratedDeriv {n : ℕ∞} : ContDiff 𝕜 n f ↔ simp only [contDiff_iff_continuous_differentiable, iteratedFDeriv_eq_equiv_comp, LinearIsometryEquiv.comp_continuous_iff, LinearIsometryEquiv.comp_differentiable_iff] +/-- The property of being `C^n`, initially defined in terms of the Fréchet derivative, can be +reformulated in terms of the one-dimensional derivative. -/ +theorem contDiff_nat_iff_iteratedDeriv {n : ℕ} : ContDiff 𝕜 n f ↔ + (∀ m : ℕ, m ≤ n → Continuous (iteratedDeriv m f)) ∧ + ∀ m : ℕ, m < n → Differentiable 𝕜 (iteratedDeriv m f) := by + rw [show n = ((n : ℕ∞) : WithTop ℕ∞) from rfl, contDiff_iff_iteratedDeriv] + simp + /-- To check that a function is `n` times continuously differentiable, it suffices to check that its first `n` derivatives are differentiable. This is slightly too strong as the condition we require on the `n`-th derivative is differentiability instead of continuity, but it has the diff --git a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean index 07e351b377405..9a682b2461766 100644 --- a/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean +++ b/Mathlib/Analysis/Calculus/LineDeriv/IntegrationByParts.lean @@ -129,14 +129,14 @@ theorem integral_bilinear_hasLineDerivAt_right_eq_neg_left_of_integrable suffices H : ∫ (x : E' × ℝ), (B (f (L.symm x))) (g' (L.symm x)) ∂ν = -∫ (x : E' × ℝ), (B (f' (L.symm x))) (g (L.symm x)) ∂ν by have : μ = Measure.map L.symm ν := by - simp [Measure.map_map L.symm.continuous.measurable L.continuous.measurable] + simp [ν, Measure.map_map L.symm.continuous.measurable L.continuous.measurable] have hL : IsClosedEmbedding L.symm := L.symm.toHomeomorph.isClosedEmbedding simpa [this, hL.integral_map] using H have L_emb : MeasurableEmbedding L := L.toHomeomorph.measurableEmbedding apply integral_bilinear_hasLineDerivAt_right_eq_neg_left_of_integrable_aux2 - · simpa [L_emb.integrable_map_iff, Function.comp_def] using hf'g - · simpa [L_emb.integrable_map_iff, Function.comp_def] using hfg' - · simpa [L_emb.integrable_map_iff, Function.comp_def] using hfg + · simpa [ν, L_emb.integrable_map_iff, Function.comp_def] using hf'g + · simpa [ν, L_emb.integrable_map_iff, Function.comp_def] using hfg' + · simpa [ν, L_emb.integrable_map_iff, Function.comp_def] using hfg · intro x have : f = (f ∘ L.symm) ∘ (L : E →ₗ[ℝ] (E' × ℝ)) := by ext y; simp specialize hf (L.symm x) diff --git a/Mathlib/Analysis/Calculus/MeanValue.lean b/Mathlib/Analysis/Calculus/MeanValue.lean index 691da7a3e6562..0fcfbf75ac5d5 100644 --- a/Mathlib/Analysis/Calculus/MeanValue.lean +++ b/Mathlib/Analysis/Calculus/MeanValue.lean @@ -552,7 +552,7 @@ theorem norm_image_sub_le_of_norm_hasFDerivWithin_le' calc ‖f y - f x - φ (y - x)‖ = ‖f y - f x - (φ y - φ x)‖ := by simp _ = ‖f y - φ y - (f x - φ x)‖ := by congr 1; abel - _ = ‖g y - g x‖ := by simp + _ = ‖g y - g x‖ := by simp [g] _ ≤ C * ‖y - x‖ := Convex.norm_image_sub_le_of_norm_hasFDerivWithin_le hg bound hs xs ys /-- Variant of the mean value inequality on a convex set. Version with `fderivWithin`. -/ diff --git a/Mathlib/Analysis/Calculus/TangentCone.lean b/Mathlib/Analysis/Calculus/TangentCone.lean index f3ac765b70a30..c818f6cfc6e58 100644 --- a/Mathlib/Analysis/Calculus/TangentCone.lean +++ b/Mathlib/Analysis/Calculus/TangentCone.lean @@ -25,9 +25,10 @@ of the derivative. This is why their names reflect their uses, and not how they ## Implementation details -Note that this file is imported by `Fderiv.Basic`. Hence, derivatives are not defined yet. The -property of uniqueness of the derivative is therefore proved in `Fderiv.Basic`, but based on the -properties of the tangent cone we prove here. +Note that this file is imported by `Mathlib.Analysis.Calculus.FDeriv.Basic`. Hence, derivatives are +not defined yet. The property of uniqueness of the derivative is therefore proved in +`Mathlib.Analysis.Calculus.FDeriv.Basic`, but based on the properties of the tangent cone we prove +here. -/ @@ -50,7 +51,8 @@ def tangentConeAt (s : Set E) (x : E) : Set E := /-- A property ensuring that the tangent cone to `s` at `x` spans a dense subset of the whole space. The main role of this property is to ensure that the differential within `s` at `x` is unique, -hence this name. The uniqueness it asserts is proved in `UniqueDiffWithinAt.eq` in `Fderiv.Basic`. +hence this name. The uniqueness it asserts is proved in `UniqueDiffWithinAt.eq` in +`Mathlib.Analysis.Calculus.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] @@ -61,7 +63,7 @@ structure UniqueDiffWithinAt (s : Set E) (x : E) : Prop where /-- A property ensuring that the tangent cone to `s` at any of its points spans a dense subset of the whole space. The main role of this property is to ensure that the differential along `s` is unique, hence this name. The uniqueness it asserts is proved in `UniqueDiffOn.eq` in -`Fderiv.Basic`. -/ +`Mathlib.Analysis.Calculus.FDeriv.Basic`. -/ def UniqueDiffOn (s : Set E) : Prop := ∀ x ∈ s, UniqueDiffWithinAt 𝕜 s x diff --git a/Mathlib/Analysis/Calculus/Taylor.lean b/Mathlib/Analysis/Calculus/Taylor.lean index 8a56fcf0d80a4..7d6b563e1c66a 100644 --- a/Mathlib/Analysis/Calculus/Taylor.lean +++ b/Mathlib/Analysis/Calculus/Taylor.lean @@ -119,8 +119,7 @@ theorem continuousOn_taylorWithinEval {f : ℝ → E} {x : ℝ} {n : ℕ} {s : S simp_rw [taylor_within_apply] refine continuousOn_finset_sum (Finset.range (n + 1)) fun i hi => ?_ refine (continuousOn_const.mul ((continuousOn_const.sub continuousOn_id).pow _)).smul ?_ - rw [show (n : WithTop ℕ∞) = (n : ℕ∞) by rfl, - contDiffOn_iff_continuousOn_differentiableOn_deriv hs] at hf + rw [contDiffOn_nat_iff_continuousOn_differentiableOn_deriv hs] at hf cases' hf with hf_left specialize hf_left i simp only [Finset.mem_range] at hi diff --git a/Mathlib/Analysis/Complex/AbsMax.lean b/Mathlib/Analysis/Complex/AbsMax.lean index 9f5038937c5e6..d2af8a302da8d 100644 --- a/Mathlib/Analysis/Complex/AbsMax.lean +++ b/Mathlib/Analysis/Complex/AbsMax.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov -/ import Mathlib.Analysis.Complex.CauchyIntegral -import Mathlib.Analysis.Normed.Module.Completion import Mathlib.Analysis.NormedSpace.Extr +import Mathlib.Data.Complex.FiniteDimensional import Mathlib.Topology.Order.ExtrClosure /-! diff --git a/Mathlib/Analysis/Complex/CauchyIntegral.lean b/Mathlib/Analysis/Complex/CauchyIntegral.lean index 5bfbd617a7f48..19be8544d83fe 100644 --- a/Mathlib/Analysis/Complex/CauchyIntegral.lean +++ b/Mathlib/Analysis/Complex/CauchyIntegral.lean @@ -8,6 +8,7 @@ import Mathlib.Analysis.Calculus.DiffContOnCl import Mathlib.Analysis.Calculus.DSlope import Mathlib.Analysis.Calculus.FDeriv.Analytic import Mathlib.Analysis.Complex.ReImTopology +import Mathlib.Data.Real.Cardinality import Mathlib.MeasureTheory.Integral.CircleIntegral import Mathlib.MeasureTheory.Integral.DivergenceTheorem import Mathlib.MeasureTheory.Measure.Lebesgue.Complex @@ -577,9 +578,9 @@ theorem _root_.DifferentiableOn.analyticOn {s : Set ℂ} {f : ℂ → E} (hd : D /-- If `f : ℂ → E` is complex differentiable on some open set `s`, then it is continuously differentiable on `s`. -/ -protected theorem _root_.DifferentiableOn.contDiffOn {s : Set ℂ} {f : ℂ → E} {n : ℕ} +protected theorem _root_.DifferentiableOn.contDiffOn {s : Set ℂ} {f : ℂ → E} {n : WithTop ℕ∞} (hd : DifferentiableOn ℂ f s) (hs : IsOpen s) : ContDiffOn ℂ n f s := - (hd.analyticOnNhd hs).contDiffOn + (hd.analyticOnNhd hs).contDiffOn_of_completeSpace /-- A complex differentiable function `f : ℂ → E` is analytic at every point. -/ protected theorem _root_.Differentiable.analyticAt {f : ℂ → E} (hf : Differentiable ℂ f) (z : ℂ) : @@ -587,7 +588,8 @@ protected theorem _root_.Differentiable.analyticAt {f : ℂ → E} (hf : Differe hf.differentiableOn.analyticAt univ_mem /-- A complex differentiable function `f : ℂ → E` is continuously differentiable at every point. -/ -protected theorem _root_.Differentiable.contDiff {f : ℂ → E} (hf : Differentiable ℂ f) {n : ℕ∞} : +protected theorem _root_.Differentiable.contDiff + {f : ℂ → E} (hf : Differentiable ℂ f) {n : WithTop ℕ∞} : ContDiff ℂ n f := contDiff_iff_contDiffAt.mpr fun z ↦ (hf.analyticAt z).contDiffAt diff --git a/Mathlib/Analysis/Complex/Conformal.lean b/Mathlib/Analysis/Complex/Conformal.lean index 18618155e7d9d..87d4b01c9333d 100644 --- a/Mathlib/Analysis/Complex/Conformal.lean +++ b/Mathlib/Analysis/Complex/Conformal.lean @@ -3,8 +3,11 @@ Copyright (c) 2021 Yourong Zang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yourong Zang -/ +import Mathlib.Analysis.Calculus.Conformal.NormedSpace +import Mathlib.Analysis.Calculus.Deriv.Basic +import Mathlib.Analysis.Calculus.FDeriv.Equiv +import Mathlib.Analysis.Calculus.FDeriv.RestrictScalars import Mathlib.Analysis.Complex.Isometry -import Mathlib.Analysis.NormedSpace.ConformalLinearMap import Mathlib.Analysis.Normed.Module.FiniteDimension import Mathlib.Data.Complex.FiniteDimensional @@ -25,10 +28,24 @@ to be conformal. linear or the composition of some complex linear map and `conj`. +* `DifferentiableAt.conformalAt` states that a real-differentiable function with a nonvanishing + differential from the complex plane into an arbitrary complex-normed space is conformal at a point + if it's holomorphic at that point. This is a version of Cauchy-Riemann equations. + +* `conformalAt_iff_differentiableAt_or_differentiableAt_comp_conj` proves that a real-differential + function with a nonvanishing differential between the complex plane is conformal at a point if and + only if it's holomorphic or antiholomorphic at that point. + ## Warning Antiholomorphic functions such as the complex conjugate are considered as conformal functions in this file. + +## TODO + +* The classical form of Cauchy-Riemann equations +* On a connected open set `u`, a function which is `ConformalAt` each point is either holomorphic +throughout or antiholomorphic throughout. -/ @@ -109,3 +126,37 @@ theorem isConformalMap_iff_is_complex_or_conj_linear : simp only [w, restrictScalars_zero, zero_comp] end ConformalIntoComplexPlane + +/-! ### Conformality of real-differentiable complex maps -/ + +section Conformality +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {z : ℂ} {f : ℂ → E} + +/-- A real differentiable function of the complex plane into some complex normed space `E` is +conformal at a point `z` if it is holomorphic at that point with a nonvanishing differential. +This is a version of the Cauchy-Riemann equations. -/ +theorem DifferentiableAt.conformalAt (h : DifferentiableAt ℂ f z) (hf' : deriv f z ≠ 0) : + ConformalAt f z := by + rw [conformalAt_iff_isConformalMap_fderiv, (h.hasFDerivAt.restrictScalars ℝ).fderiv] + apply isConformalMap_complex_linear + simpa only [Ne, ContinuousLinearMap.ext_ring_iff] + +/-- A complex function is conformal if and only if the function is holomorphic or antiholomorphic +with a nonvanishing differential. -/ +theorem conformalAt_iff_differentiableAt_or_differentiableAt_comp_conj {f : ℂ → ℂ} {z : ℂ} : + ConformalAt f z ↔ + (DifferentiableAt ℂ f z ∨ DifferentiableAt ℂ (f ∘ conj) (conj z)) ∧ fderiv ℝ f z ≠ 0 := by + rw [conformalAt_iff_isConformalMap_fderiv] + rw [isConformalMap_iff_is_complex_or_conj_linear] + apply and_congr_left + intro h + have h_diff := h.imp_symm fderiv_zero_of_not_differentiableAt + apply or_congr + · rw [differentiableAt_iff_restrictScalars ℝ h_diff] + rw [← conj_conj z] at h_diff + rw [differentiableAt_iff_restrictScalars ℝ (h_diff.comp _ conjCLE.differentiableAt)] + refine exists_congr fun g => rfl.congr ?_ + have : fderiv ℝ conj (conj z) = _ := conjCLE.fderiv + simp [fderiv_comp _ h_diff conjCLE.differentiableAt, this, conj_conj] + +end Conformality diff --git a/Mathlib/Analysis/Complex/Isometry.lean b/Mathlib/Analysis/Complex/Isometry.lean index 57ac151acc4e2..c2cf8a9bc727c 100644 --- a/Mathlib/Analysis/Complex/Isometry.lean +++ b/Mathlib/Analysis/Complex/Isometry.lean @@ -130,7 +130,7 @@ theorem linear_isometry_complex (f : ℂ ≃ₗᵢ[ℝ] ℂ) : ∃ a : Circle, f = rotation a ∨ f = conjLIE.trans (rotation a) := by let a : Circle := ⟨f 1, by simp [Submonoid.unitSphere, ← Complex.norm_eq_abs, f.norm_map]⟩ use a - have : (f.trans (rotation a).symm) 1 = 1 := by simpa using rotation_apply a⁻¹ (f 1) + have : (f.trans (rotation a).symm) 1 = 1 := by simpa [a] using rotation_apply a⁻¹ (f 1) refine (linear_isometry_complex_aux this).imp (fun h₁ => ?_) fun h₂ => ?_ · simpa using eq_mul_of_inv_mul_eq h₁ · exact eq_mul_of_inv_mul_eq h₂ diff --git a/Mathlib/Analysis/Complex/RealDeriv.lean b/Mathlib/Analysis/Complex/RealDeriv.lean index 1609fa5e357a4..92f1c438dbbbb 100644 --- a/Mathlib/Analysis/Complex/RealDeriv.lean +++ b/Mathlib/Analysis/Complex/RealDeriv.lean @@ -5,34 +5,17 @@ Authors: Sébastien Gouëzel, Yourong Zang -/ import Mathlib.Analysis.Calculus.ContDiff.Basic import Mathlib.Analysis.Calculus.Deriv.Linear -import Mathlib.Analysis.Complex.Conformal -import Mathlib.Analysis.Calculus.Conformal.NormedSpace +import Mathlib.Analysis.Complex.Basic /-! # Real differentiability of complex-differentiable functions `HasDerivAt.real_of_complex` expresses that, if a function on `ℂ` is differentiable (over `ℂ`), then its restriction to `ℝ` is differentiable over `ℝ`, with derivative the real part of the complex derivative. - -`DifferentiableAt.conformalAt` states that a real-differentiable function with a nonvanishing -differential from the complex plane into an arbitrary complex-normed space is conformal at a point -if it's holomorphic at that point. This is a version of Cauchy-Riemann equations. - -`conformalAt_iff_differentiableAt_or_differentiableAt_comp_conj` proves that a real-differential -function with a nonvanishing differential between the complex plane is conformal at a point if and -only if it's holomorphic or antiholomorphic at that point. - -## TODO - -* The classical form of Cauchy-Riemann equations -* On a connected open set `u`, a function which is `ConformalAt` each point is either holomorphic -throughout or antiholomorphic throughout. - -## Warning - -We do NOT require conformal functions to be orientation-preserving in this file. -/ +assert_not_exists IsConformalMap +assert_not_exists Conformal section RealDerivOfComplex @@ -131,42 +114,3 @@ theorem HasDerivAt.ofReal_comp {f : ℝ → ℝ} {u : ℝ} (hf : HasDerivAt f u ofRealCLM.hasDerivAt.scomp z hf end RealDerivOfComplex - -section Conformality - -/-! ### Conformality of real-differentiable complex maps -/ - -open Complex ContinuousLinearMap - -open scoped ComplexConjugate - -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℂ E] {z : ℂ} {f : ℂ → E} - -/-- A real differentiable function of the complex plane into some complex normed space `E` is - conformal at a point `z` if it is holomorphic at that point with a nonvanishing differential. - This is a version of the Cauchy-Riemann equations. -/ -theorem DifferentiableAt.conformalAt (h : DifferentiableAt ℂ f z) (hf' : deriv f z ≠ 0) : - ConformalAt f z := by - rw [conformalAt_iff_isConformalMap_fderiv, (h.hasFDerivAt.restrictScalars ℝ).fderiv] - apply isConformalMap_complex_linear - simpa only [Ne, ContinuousLinearMap.ext_ring_iff] - -/-- A complex function is conformal if and only if the function is holomorphic or antiholomorphic - with a nonvanishing differential. -/ -theorem conformalAt_iff_differentiableAt_or_differentiableAt_comp_conj {f : ℂ → ℂ} {z : ℂ} : - ConformalAt f z ↔ - (DifferentiableAt ℂ f z ∨ DifferentiableAt ℂ (f ∘ conj) (conj z)) ∧ fderiv ℝ f z ≠ 0 := by - rw [conformalAt_iff_isConformalMap_fderiv] - rw [isConformalMap_iff_is_complex_or_conj_linear] - apply and_congr_left - intro h - have h_diff := h.imp_symm fderiv_zero_of_not_differentiableAt - apply or_congr - · rw [differentiableAt_iff_restrictScalars ℝ h_diff] - rw [← conj_conj z] at h_diff - rw [differentiableAt_iff_restrictScalars ℝ (h_diff.comp _ conjCLE.differentiableAt)] - refine exists_congr fun g => rfl.congr ?_ - have : fderiv ℝ conj (conj z) = _ := conjCLE.fderiv - simp [fderiv_comp _ h_diff conjCLE.differentiableAt, this, conj_conj] - -end Conformality diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean index 88a6d6642a9b9..c92c0c0ce665b 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Metric.lean @@ -157,8 +157,14 @@ theorem cmp_dist_eq_cmp_dist_coe_center (z w : ℍ) (r : ℝ) : ((mul_neg_of_pos_of_neg w.im_pos (sinh_neg_iff.2 hr₀)).trans_le dist_nonneg).cmp_eq_gt.symm] have hr₀' : 0 ≤ w.im * Real.sinh r := by positivity have hzw₀ : 0 < 2 * z.im * w.im := by positivity - simp only [← cosh_strictMonoOn.cmp_map_eq dist_nonneg hr₀, ← - (pow_left_strictMonoOn₀ two_ne_zero).cmp_map_eq dist_nonneg hr₀', dist_coe_center_sq] + #adaptation_note + /-- + After the bug fix in https://github.com/leanprover/lean4/pull/6024, + we need to give Lean the hint `(y := w.im * Real.sinh r)`. + -/ + simp only [← cosh_strictMonoOn.cmp_map_eq dist_nonneg hr₀, + ← (pow_left_strictMonoOn₀ two_ne_zero).cmp_map_eq dist_nonneg (y := w.im * Real.sinh r) hr₀', + dist_coe_center_sq] rw [← cmp_mul_pos_left hzw₀, ← cmp_sub_zero, ← mul_sub, ← cmp_add_right, zero_add] theorem dist_eq_iff_dist_coe_center_eq : diff --git a/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean b/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean index ac416004b29f9..e152fc2ea4eac 100644 --- a/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean +++ b/Mathlib/Analysis/Complex/UpperHalfPlane/Topology.lean @@ -5,7 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Analysis.Complex.UpperHalfPlane.Basic import Mathlib.Analysis.Convex.Contractible -import Mathlib.Analysis.Convex.Normed +import Mathlib.Analysis.LocallyConvex.WithSeminorms import Mathlib.Analysis.Complex.Convex import Mathlib.Analysis.Complex.ReImTopology import Mathlib.Topology.Homotopy.Contractible @@ -110,7 +110,7 @@ theorem ModularGroup_T_zpow_mem_verticalStrip (z : ℍ) {N : ℕ} (hn : 0 < N) : refine ⟨?_, (by simp only [mul_neg, Int.cast_neg, Int.cast_mul, Int.cast_natCast, vadd_im, le_refl])⟩ have h : (N * (-n : ℝ) +ᵥ z).re = -N * Int.floor (z.re / N) + z.re := by - simp only [Int.cast_natCast, mul_neg, vadd_re, neg_mul] + simp only [n, Int.cast_natCast, mul_neg, vadd_re, neg_mul] norm_cast at * rw [h, add_comm] simp only [neg_mul, Int.cast_neg, Int.cast_mul, Int.cast_natCast] diff --git a/Mathlib/Analysis/ConstantSpeed.lean b/Mathlib/Analysis/ConstantSpeed.lean index 268a8fb396472..308cfdf9f15ce 100644 --- a/Mathlib/Analysis/ConstantSpeed.lean +++ b/Mathlib/Analysis/ConstantSpeed.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémi Bottinelli -/ import Mathlib.Data.Set.Function -import Mathlib.Analysis.BoundedVariation +import Mathlib.Analysis.RCLike.Basic +import Mathlib.Topology.EMetricSpace.BoundedVariation /-! # Constant speed @@ -40,7 +41,7 @@ arc-length, parameterization open scoped NNReal ENNReal -open Set MeasureTheory +open Set variable {α : Type*} [LinearOrder α] {E : Type*} [PseudoEMetricSpace E] variable (f : ℝ → E) (s : Set ℝ) (l : ℝ≥0) diff --git a/Mathlib/Analysis/Convex/Between.lean b/Mathlib/Analysis/Convex/Between.lean index 0359b1ad4b711..977702d9c6a6b 100644 --- a/Mathlib/Analysis/Convex/Between.lean +++ b/Mathlib/Analysis/Convex/Between.lean @@ -153,14 +153,16 @@ theorem Function.Injective.sbtw_map_iff {x y z : P} {f : P →ᵃ[R] P'} (hf : F @[simp] theorem AffineEquiv.wbtw_map_iff {x y z : P} (f : P ≃ᵃ[R] P') : Wbtw R (f x) (f y) (f z) ↔ Wbtw R x y z := by - refine Function.Injective.wbtw_map_iff (?_ : Function.Injective f.toAffineMap) - exact f.injective + have : Function.Injective f.toAffineMap := f.injective + -- `refine` or `exact` are very slow, `apply` is fast. Please check before golfing. + apply this.wbtw_map_iff @[simp] theorem AffineEquiv.sbtw_map_iff {x y z : P} (f : P ≃ᵃ[R] P') : Sbtw R (f x) (f y) (f z) ↔ Sbtw R x y z := by - refine Function.Injective.sbtw_map_iff (?_ : Function.Injective f.toAffineMap) - exact f.injective + have : Function.Injective f.toAffineMap := f.injective + -- `refine` or `exact` are very slow, `apply` is fast. Please check before golfing. + apply this.sbtw_map_iff @[simp] theorem wbtw_const_vadd_iff {x y z : P} (v : V) : diff --git a/Mathlib/Analysis/Convex/Birkhoff.lean b/Mathlib/Analysis/Convex/Birkhoff.lean index 702bc496c5a0d..d69061ff3199b 100644 --- a/Mathlib/Analysis/Convex/Birkhoff.lean +++ b/Mathlib/Analysis/Convex/Birkhoff.lean @@ -48,7 +48,7 @@ private lemma exists_perm_eq_zero_implies_eq_zero [Nonempty n] {s : R} (hs : 0 < rw [exists_mem_doublyStochastic_eq_smul_iff hs.le] at hM let f (i : n) : Finset n := {j | M i j ≠ 0} have hf (A : Finset n) : #A ≤ #(A.biUnion f) := by - have (i) : ∑ j ∈ f i, M i j = s := by simp [sum_subset (filter_subset _ _), hM.2.1] + have (i) : ∑ j ∈ f i, M i j = s := by simp [f, sum_subset (filter_subset _ _), hM.2.1] have h₁ : ∑ i ∈ A, ∑ j ∈ f i, M i j = #A * s := by simp [this] have h₂ : ∑ i, ∑ j ∈ A.biUnion f, M i j = #(A.biUnion f) * s := by simp [sum_comm (t := A.biUnion f), hM.2.2, mul_comm s] @@ -110,7 +110,7 @@ private lemma doublyStochastic_sum_perm_aux (M : Matrix n n R) simp only [sub_apply, smul_apply, PEquiv.toMatrix_apply, Equiv.toPEquiv_apply, Option.mem_def, Option.some.injEq, smul_eq_mul, mul_ite, mul_one, mul_zero, sub_nonneg, sum_sub_distrib, sum_ite_eq, mem_univ, ↓reduceIte, N] - refine ⟨fun i' j => ?_, by simp [hM.2.1], by simp [← σ.eq_symm_apply, hM]⟩ + refine ⟨fun i' j => ?_, by simp [s', hM.2.1], by simp [s', ← σ.eq_symm_apply, hM]⟩ split case isTrue h => exact (hi' i' (by simp)).trans_eq (by rw [h]) case isFalse h => exact hM.1 _ _ diff --git a/Mathlib/Analysis/Convex/Combination.lean b/Mathlib/Analysis/Convex/Combination.lean index 777e221c7f434..983f2d7608437 100644 --- a/Mathlib/Analysis/Convex/Combination.lean +++ b/Mathlib/Analysis/Convex/Combination.lean @@ -285,7 +285,7 @@ theorem convexHull_range_eq_exists_affineCombination (v : ι → E) : convexHull · rintro i - by_cases hi : i ∈ s <;> by_cases hi' : i ∈ s' <;> simp [W, hi, hi', add_nonneg, mul_nonneg ha (hw₀ i _), mul_nonneg hb (hw₀' i _)] - · simp_rw [affineCombination_eq_linear_combination (s ∪ s') v _ hW₁, + · simp_rw [W, affineCombination_eq_linear_combination (s ∪ s') v _ hW₁, affineCombination_eq_linear_combination s v w hw₁, affineCombination_eq_linear_combination s' v w' hw₁', add_smul, sum_add_distrib] rw [← sum_subset subset_union_left, ← sum_subset subset_union_right] diff --git a/Mathlib/Analysis/Convex/Cone/Basic.lean b/Mathlib/Analysis/Convex/Cone/Basic.lean index e4fb40b9a90ef..303a1a919f4f2 100644 --- a/Mathlib/Analysis/Convex/Cone/Basic.lean +++ b/Mathlib/Analysis/Convex/Cone/Basic.lean @@ -39,6 +39,7 @@ While `Convex 𝕜` is a predicate on sets, `ConvexCone 𝕜 E` is a bundled con assert_not_exists NormedSpace assert_not_exists Real +assert_not_exists Cardinal open Set LinearMap diff --git a/Mathlib/Analysis/Convex/Cone/Extension.lean b/Mathlib/Analysis/Convex/Cone/Extension.lean index 31d7448ecb98e..31471bbcab337 100644 --- a/Mathlib/Analysis/Convex/Cone/Extension.lean +++ b/Mathlib/Analysis/Convex/Cone/Extension.lean @@ -68,7 +68,7 @@ theorem step (nonneg : ∀ x : f.domain, (x : E) ∈ s → 0 ≤ f x) set Sp := f '' { x : f.domain | (x : E) + y ∈ s } set Sn := f '' { x : f.domain | -(x : E) - y ∈ s } suffices (upperBounds Sn ∩ lowerBounds Sp).Nonempty by - simpa only [Set.Nonempty, upperBounds, lowerBounds, forall_mem_image] using this + simpa only [Sp, Sn, Set.Nonempty, upperBounds, lowerBounds, forall_mem_image] using this refine exists_between_of_forall_le (Nonempty.image f ?_) (Nonempty.image f (dense y)) ?_ · rcases dense (-y) with ⟨x, hx⟩ rw [← neg_neg x, NegMemClass.coe_neg, ← sub_eq_add_neg] at hx diff --git a/Mathlib/Analysis/Convex/Jensen.lean b/Mathlib/Analysis/Convex/Jensen.lean index 044b54d8b3d24..332967af25195 100644 --- a/Mathlib/Analysis/Convex/Jensen.lean +++ b/Mathlib/Analysis/Convex/Jensen.lean @@ -110,7 +110,7 @@ lemma StrictConvexOn.map_sum_lt (hf : StrictConvexOn 𝕜 s f) (h₀ : ∀ i ∈ have hk : k ∉ u := by simp [u] have ht : t = (u.cons k hk).cons j (mem_cons.not.2 <| not_or_intro (ne_of_apply_ne _ hjk) hj) := by - simp [insert_erase this, insert_erase ‹j ∈ t›, *] + simp [u, insert_erase this, insert_erase ‹j ∈ t›, *] clear_value u subst ht simp only [sum_cons] diff --git a/Mathlib/Analysis/Convex/Normed.lean b/Mathlib/Analysis/Convex/Normed.lean index 9a305c1457de0..2277ac898fcf3 100644 --- a/Mathlib/Analysis/Convex/Normed.lean +++ b/Mathlib/Analysis/Convex/Normed.lean @@ -111,10 +111,6 @@ theorem isBounded_convexHull {s : Set E} : instance (priority := 100) NormedSpace.instPathConnectedSpace : PathConnectedSpace E := TopologicalAddGroup.pathConnectedSpace -instance (priority := 100) NormedSpace.instLocPathConnectedSpace : LocPathConnectedSpace E := - .of_bases (fun _ => Metric.nhds_basis_ball) fun x r r_pos => - (convex_ball x r).isPathConnected <| by simp [r_pos] - theorem Wbtw.dist_add_dist {x y z : P} (h : Wbtw ℝ x y z) : dist x y + dist y z = dist x z := by obtain ⟨a, ⟨ha₀, ha₁⟩, rfl⟩ := h diff --git a/Mathlib/Analysis/Convex/Radon.lean b/Mathlib/Analysis/Convex/Radon.lean index 21470d3e027c9..ae64b4a1822a7 100644 --- a/Mathlib/Analysis/Convex/Radon.lean +++ b/Mathlib/Analysis/Convex/Radon.lean @@ -212,7 +212,7 @@ If `F` is a (possibly infinite) family of more than `d + 1` compact convex sets finite dimension `d`, and any `d + 1` sets of `F` intersect nontrivially, then all sets of `F` intersect nontrivially. -/ theorem helly_theorem_compact [TopologicalSpace E] [T2Space E] {F : ι → Set E} - (h_card : finrank 𝕜 E + 1 ≤ PartENat.card ι) + (h_card : finrank 𝕜 E + 1 ≤ ENat.card ι) (h_convex : ∀ i, Convex 𝕜 (F i)) (h_compact : ∀ i, IsCompact (F i)) (h_inter : ∀ I : Finset ι, #I = finrank 𝕜 E + 1 → (⋂ i ∈ I, F i).Nonempty) : (⋂ i, F i).Nonempty := by @@ -224,7 +224,7 @@ theorem helly_theorem_compact [TopologicalSpace E] [T2Space E] {F : ι → Set E · have : Finite ι := Finite.of_not_infinite h have : Fintype ι := Fintype.ofFinite ι apply exists_superset_card_eq hI_card - simp only [PartENat.card_eq_coe_fintype_card] at h_card + simp only [ENat.card_eq_coe_fintype_card] at h_card rwa [← Nat.cast_one, ← Nat.cast_add, Nat.cast_le] at h_card obtain ⟨J, hJ_ss, hJ_card⟩ := hJ apply Set.Nonempty.mono <| biInter_mono hJ_ss (by intro _ _; rfl) diff --git a/Mathlib/Analysis/Convex/Topology.lean b/Mathlib/Analysis/Convex/Topology.lean index ac81c76f071c7..4fe7a8fcd272e 100644 --- a/Mathlib/Analysis/Convex/Topology.lean +++ b/Mathlib/Analysis/Convex/Topology.lean @@ -268,6 +268,31 @@ protected theorem Convex.strictConvex {s : Set E} (hs : Convex 𝕜 s) end ContinuousConstSMul +section ContinuousSMul + +variable [LinearOrderedField 𝕜] [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] + [TopologicalAddGroup E] [TopologicalSpace 𝕜] [OrderTopology 𝕜] [ContinuousSMul 𝕜 E] + +theorem Convex.closure_interior_eq_closure_of_nonempty_interior {s : Set E} (hs : Convex 𝕜 s) + (hs' : (interior s).Nonempty) : closure (interior s) = closure s := + subset_antisymm (closure_mono interior_subset) + fun _ h ↦ closure_mono (hs.openSegment_interior_closure_subset_interior hs'.choose_spec h) + (segment_subset_closure_openSegment (right_mem_segment ..)) + +theorem Convex.interior_closure_eq_interior_of_nonempty_interior {s : Set E} (hs : Convex 𝕜 s) + (hs' : (interior s).Nonempty) : interior (closure s) = interior s := by + refine subset_antisymm ?_ (interior_mono subset_closure) + intro y hy + rcases hs' with ⟨x, hx⟩ + have h := AffineMap.lineMap_apply_one (k := 𝕜) x y + obtain ⟨t, ht1, ht⟩ := AffineMap.lineMap_continuous.tendsto' _ _ h |>.eventually_mem + (mem_interior_iff_mem_nhds.1 hy) |>.exists_gt + apply hs.openSegment_interior_closure_subset_interior hx ht + nth_rw 1 [← AffineMap.lineMap_apply_zero (k := 𝕜) x y, ← image_openSegment] + exact ⟨1, Ioo_subset_openSegment ⟨zero_lt_one, ht1⟩, h⟩ + +end ContinuousSMul + section TopologicalSpace variable [OrderedSemiring 𝕜] [AddCommGroup E] [Module 𝕜 E] [TopologicalSpace E] diff --git a/Mathlib/Analysis/Convolution.lean b/Mathlib/Analysis/Convolution.lean index f2e6fd1a550aa..9363b3cee07de 100644 --- a/Mathlib/Analysis/Convolution.lean +++ b/Mathlib/Analysis/Convolution.lean @@ -1190,7 +1190,7 @@ theorem contDiffOn_convolution_right_with_param_aux {G : Type uP} {E' : Type uP} HasFDerivAt (fun q : P × G => (f ⋆[L, μ] g q.1) q.2) (f' q₀.1 q₀.2) q₀ := hasFDerivAt_convolution_right_with_param L hs hk hgs hf hg.one_of_succ rw [contDiffOn_succ_iff_fderiv_of_isOpen (hs.prod (@isOpen_univ G _))] at hg ⊢ - refine ⟨?_, ?_⟩ + refine ⟨?_, by simp, ?_⟩ · rintro ⟨p, x⟩ ⟨hp, -⟩ exact (A (p, x) hp).differentiableAt.differentiableWithinAt · suffices H : ContDiffOn 𝕜 n (↿f') (s ×ˢ univ) by @@ -1207,9 +1207,9 @@ theorem contDiffOn_convolution_right_with_param_aux {G : Type uP} {E' : Type uP} rintro ⟨p, y⟩ ⟨hp, hy⟩ exact hgs p y hp hy apply ih (L.precompR (P × G) : _) B - convert hg.2 + convert hg.2.2 | htop ih => - rw [contDiffOn_top] at hg ⊢ + rw [contDiffOn_infty] at hg ⊢ exact fun n ↦ ih n L hgs (hg n) /-- The convolution `f * g` is `C^n` when `f` is locally integrable and `g` is `C^n` and compactly diff --git a/Mathlib/Analysis/Distribution/SchwartzSpace.lean b/Mathlib/Analysis/Distribution/SchwartzSpace.lean index b1f19e08a826b..c5823ee573914 100644 --- a/Mathlib/Analysis/Distribution/SchwartzSpace.lean +++ b/Mathlib/Analysis/Distribution/SchwartzSpace.lean @@ -545,7 +545,7 @@ lemma _root_.Function.HasTemperateGrowth.of_fderiv {f : E → F} (h'f : Function.HasTemperateGrowth (fderiv ℝ f)) (hf : Differentiable ℝ f) {k : ℕ} {C : ℝ} (h : ∀ x, ‖f x‖ ≤ C * (1 + ‖x‖) ^ k) : Function.HasTemperateGrowth f := by - refine ⟨contDiff_top_iff_fderiv.2 ⟨hf, h'f.1⟩ , fun n ↦ ?_⟩ + refine ⟨contDiff_succ_iff_fderiv.2 ⟨hf, by simp, h'f.1⟩ , fun n ↦ ?_⟩ rcases n with rfl|m · exact ⟨k, C, fun x ↦ by simpa using h x⟩ · rcases h'f.2 m with ⟨k', C', h'⟩ @@ -755,14 +755,15 @@ end EvalCLM section Multiplication -variable [NormedAddCommGroup D] [NormedSpace ℝ D] -variable [NormedAddCommGroup G] [NormedSpace ℝ G] +variable [NontriviallyNormedField 𝕜] [NormedAlgebra ℝ 𝕜] + [NormedAddCommGroup D] [NormedSpace ℝ D] + [NormedAddCommGroup G] [NormedSpace ℝ G] + [NormedSpace 𝕜 E] [NormedSpace 𝕜 F] [NormedSpace 𝕜 G] /-- The map `f ↦ (x ↦ B (f x) (g x))` as a continuous `𝕜`-linear map on Schwartz space, where `B` is a continuous `𝕜`-linear map and `g` is a function of temperate growth. -/ -def bilinLeftCLM (B : E →L[ℝ] F →L[ℝ] G) {g : D → F} (hg : g.HasTemperateGrowth) : - 𝓢(D, E) →L[ℝ] 𝓢(D, G) := by - -- Todo (after port): generalize to `B : E →L[𝕜] F →L[𝕜] G` and `𝕜`-linear +def bilinLeftCLM (B : E →L[𝕜] F →L[𝕜] G) {g : D → F} (hg : g.HasTemperateGrowth) : + 𝓢(D, E) →L[𝕜] 𝓢(D, G) := by refine mkCLM (fun f x => B (f x) (g x)) (fun _ _ _ => by simp only [map_add, add_left_inj, Pi.add_apply, eq_self_iff_true, @@ -770,7 +771,8 @@ def bilinLeftCLM (B : E →L[ℝ] F →L[ℝ] G) {g : D → F} (hg : g.HasTemper (fun _ _ _ => by simp only [smul_apply, map_smul, ContinuousLinearMap.coe_smul', Pi.smul_apply, RingHom.id_apply]) - (fun f => (B.isBoundedBilinearMap.contDiff.restrict_scalars ℝ).comp (f.smooth'.prod hg.1)) ?_ + (fun f => (B.bilinearRestrictScalars ℝ).isBoundedBilinearMap.contDiff.comp + (f.smooth'.prod hg.1)) ?_ rintro ⟨k, n⟩ rcases hg.norm_iteratedFDeriv_le_uniform_aux n with ⟨l, C, hC, hgrowth⟩ use @@ -778,10 +780,12 @@ def bilinLeftCLM (B : E →L[ℝ] F →L[ℝ] G) {g : D → F} (hg : g.HasTemper by positivity intro f x have hxk : 0 ≤ ‖x‖ ^ k := by positivity + simp_rw [← ContinuousLinearMap.bilinearRestrictScalars_apply_apply ℝ B] have hnorm_mul := - ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear B f.smooth' hg.1 x (n := n) - (mod_cast le_top) + ContinuousLinearMap.norm_iteratedFDeriv_le_of_bilinear (B.bilinearRestrictScalars ℝ) + f.smooth' hg.1 x (n := n) (mod_cast le_top) refine le_trans (mul_le_mul_of_nonneg_left hnorm_mul hxk) ?_ + rw [ContinuousLinearMap.norm_bilinearRestrictScalars] move_mul [← ‖B‖] simp_rw [mul_assoc ‖B‖] gcongr _ * ?_ @@ -934,7 +938,7 @@ variable [RCLike 𝕜] [NormedSpace 𝕜 F] [SMulCommClass ℝ 𝕜 F] def fderivCLM : 𝓢(E, F) →L[𝕜] 𝓢(E, E →L[ℝ] F) := mkCLM (fderiv ℝ) (fun f g _ => fderiv_add f.differentiableAt g.differentiableAt) (fun a f _ => fderiv_const_smul f.differentiableAt a) - (fun f => (contDiff_top_iff_fderiv.mp f.smooth').2) fun ⟨k, n⟩ => + (fun f => (contDiff_succ_iff_fderiv.mp f.smooth').2.2) fun ⟨k, n⟩ => ⟨{⟨k, n + 1⟩}, 1, zero_le_one, fun f x => by simpa only [schwartzSeminormFamily_apply, Seminorm.comp_apply, Finset.sup_singleton, one_smul, norm_iteratedFDeriv_fderiv, one_mul] using f.le_seminorm 𝕜 k (n + 1) x⟩ @@ -947,7 +951,7 @@ theorem fderivCLM_apply (f : 𝓢(E, F)) (x : E) : fderivCLM 𝕜 f x = fderiv def derivCLM : 𝓢(ℝ, F) →L[𝕜] 𝓢(ℝ, F) := mkCLM deriv (fun f g _ => deriv_add f.differentiableAt g.differentiableAt) (fun a f _ => deriv_const_smul a f.differentiableAt) - (fun f => (contDiff_top_iff_deriv.mp f.smooth').2) fun ⟨k, n⟩ => + (fun f => (contDiff_succ_iff_deriv.mp f.smooth').2.2) fun ⟨k, n⟩ => ⟨{⟨k, n + 1⟩}, 1, zero_le_one, fun f x => by simpa only [Real.norm_eq_abs, Finset.sup_singleton, schwartzSeminormFamily_apply, one_mul, norm_iteratedFDeriv_eq_norm_iteratedDeriv, ← iteratedDeriv_succ'] using diff --git a/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean b/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean index 08b29d45a4d25..367aebfa1d6f8 100644 --- a/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean +++ b/Mathlib/Analysis/Fourier/RiemannLebesgueLemma.lean @@ -116,7 +116,7 @@ theorem tendsto_integral_exp_inner_smul_cocompact_of_continuous_compact_support suffices A = Metric.closedBall (0 : V) (R + 1) by rw [this] exact Metric.isClosed_ball.measurableSet - simp_rw [Metric.closedBall, dist_eq_norm, sub_zero] + simp_rw [A, Metric.closedBall, dist_eq_norm, sub_zero] obtain ⟨B, hB_pos, hB_vol⟩ : ∃ B : ℝ≥0, 0 < B ∧ volume A ≤ B := by have hc : IsCompact A := by simpa only [Metric.closedBall, dist_eq_norm, sub_zero] using isCompact_closedBall (0 : V) _ diff --git a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean index 12f3131cc2e8b..660294ee97883 100644 --- a/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean +++ b/Mathlib/Analysis/FunctionalSpaces/SobolevInequality.lean @@ -336,8 +336,11 @@ theorem lintegral_pow_le_pow_lintegral_fderiv_aux [Fintype ι] · exact hu.comp (by convert contDiff_update 1 x i) · exact h2u.comp_isClosedEmbedding (isClosedEmbedding_update x i) _ ≤ ∫⁻ xᵢ, (‖fderiv ℝ u (update x i xᵢ)‖₊ : ℝ≥0∞) := ?_ - gcongr with y; swap + gcongr · exact Measure.restrict_le_self + intro y + dsimp + gcongr -- bound the derivative which appears calc ‖deriv (u ∘ update x i) y‖₊ = ‖fderiv ℝ u (update x i y) (deriv (update x i) y)‖₊ := by rw [fderiv_comp_deriv _ (hu.differentiable le_rfl).differentiableAt @@ -680,7 +683,10 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_le [FiniteDimensional ℝ F] have hp' : p'⁻¹ = p⁻¹ - (finrank ℝ E : ℝ)⁻¹ := by rw [inv_inv, NNReal.coe_sub] · simp - · gcongr + · #adaptation_note + /-- This should just be `gcongr`, but this is not working as of nightly-2024-11-20. + Possibly related to #19262 (since this proof fails at `with_reducible_and_instances`). -/ + exact inv_anti₀ (by positivity) h2p.le have : (q : ℝ≥0∞) ≤ p' := by have H : (p' : ℝ)⁻¹ ≤ (↑q)⁻¹ := trans hp' hpq norm_cast at H ⊢ @@ -688,7 +694,10 @@ theorem eLpNorm_le_eLpNorm_fderiv_of_le [FiniteDimensional ℝ F] · dsimp have : 0 < p⁻¹ - (finrank ℝ E : ℝ≥0)⁻¹ := by simp only [tsub_pos_iff_lt] - gcongr + #adaptation_note + /-- This should just be `gcongr`, but this is not working as of nightly-2024-11-20. + Possibly related to #19262 (since this proof fails at `with_reducible_and_instances`). -/ + exact inv_strictAnti₀ (by positivity) h2p positivity · positivity set t := (μ s).toNNReal ^ (1 / q - 1 / p' : ℝ) diff --git a/Mathlib/Analysis/InnerProductSpace/Calculus.lean b/Mathlib/Analysis/InnerProductSpace/Calculus.lean index 6fff4e5ede2f4..dcbeab2b02667 100644 --- a/Mathlib/Analysis/InnerProductSpace/Calculus.lean +++ b/Mathlib/Analysis/InnerProductSpace/Calculus.lean @@ -61,7 +61,7 @@ theorem differentiable_inner : Differentiable ℝ fun p : E × E => ⟪p.1, p.2 variable (𝕜) variable {G : Type*} [NormedAddCommGroup G] [NormedSpace ℝ G] {f g : G → E} {f' g' : G →L[ℝ] E} - {s : Set G} {x : G} {n : ℕ∞} + {s : Set G} {x : G} {n : WithTop ℕ∞} theorem ContDiffWithinAt.inner (hf : ContDiffWithinAt ℝ n f s x) (hg : ContDiffWithinAt ℝ n g s x) : ContDiffWithinAt ℝ n (fun x => ⟪f x, g x⟫) s x := @@ -302,19 +302,19 @@ theorem hasFDerivWithinAt_euclidean : ∀ i, HasFDerivWithinAt (fun x => f x i) (PiLp.proj _ _ i ∘L f') t y := hasFDerivWithinAt_piLp _ -theorem contDiffWithinAt_euclidean {n : ℕ∞} : +theorem contDiffWithinAt_euclidean {n : WithTop ℕ∞} : ContDiffWithinAt 𝕜 n f t y ↔ ∀ i, ContDiffWithinAt 𝕜 n (fun x => f x i) t y := contDiffWithinAt_piLp _ -theorem contDiffAt_euclidean {n : ℕ∞} : +theorem contDiffAt_euclidean {n : WithTop ℕ∞} : ContDiffAt 𝕜 n f y ↔ ∀ i, ContDiffAt 𝕜 n (fun x => f x i) y := contDiffAt_piLp _ -theorem contDiffOn_euclidean {n : ℕ∞} : +theorem contDiffOn_euclidean {n : WithTop ℕ∞} : ContDiffOn 𝕜 n f t ↔ ∀ i, ContDiffOn 𝕜 n (fun x => f x i) t := contDiffOn_piLp _ -theorem contDiff_euclidean {n : ℕ∞} : ContDiff 𝕜 n f ↔ ∀ i, ContDiff 𝕜 n fun x => f x i := +theorem contDiff_euclidean {n : WithTop ℕ∞} : ContDiff 𝕜 n f ↔ ∀ i, ContDiff 𝕜 n fun x => f x i := contDiff_piLp _ end PiLike diff --git a/Mathlib/Analysis/InnerProductSpace/PiL2.lean b/Mathlib/Analysis/InnerProductSpace/PiL2.lean index 227dd212a2354..4813828390c93 100644 --- a/Mathlib/Analysis/InnerProductSpace/PiL2.lean +++ b/Mathlib/Analysis/InnerProductSpace/PiL2.lean @@ -7,6 +7,7 @@ import Mathlib.Analysis.InnerProductSpace.Projection import Mathlib.Analysis.Normed.Lp.PiLp import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.LinearAlgebra.UnitaryGroup +import Mathlib.Util.Superscript /-! # `L²` inner product space structure on finite products of inner product spaces @@ -30,7 +31,8 @@ the last section, various properties of matrices are explored. - `EuclideanSpace 𝕜 n`: defined to be `PiLp 2 (n → 𝕜)` for any `Fintype n`, i.e., the space from functions to `n` to `𝕜` with the `L²` norm. We register several instances on it (notably - that it is a finite-dimensional inner product space). + that it is a finite-dimensional inner product space), and provide a `!ₚ[]` notation (for numeric + subscripts like `₂`) for the case when the indexing type is `Fin n`. - `OrthonormalBasis 𝕜 ι`: defined to be an isometry to Euclidean space from a given finite-dimensional inner product space, `E ≃ₗᵢ[𝕜] EuclideanSpace 𝕜 ι`. @@ -95,10 +97,43 @@ theorem PiLp.inner_apply {ι : Type*} [Fintype ι] {f : ι → Type*} [∀ i, No rfl /-- The standard real/complex Euclidean space, functions on a finite type. For an `n`-dimensional -space use `EuclideanSpace 𝕜 (Fin n)`. -/ +space use `EuclideanSpace 𝕜 (Fin n)`. + +For the case when `n = Fin _`, there is `!₂[x, y, ...]` notation for building elements of this type, +analogous to `![x, y, ...]` notation. -/ abbrev EuclideanSpace (𝕜 : Type*) (n : Type*) : Type _ := PiLp 2 fun _ : n => 𝕜 +section Notation +open Lean Meta Elab Term Macro TSyntax PrettyPrinter.Delaborator SubExpr + +/-- Notation for vectors in Lp space. `!₂[x, y, ...]` is a shorthand for +`(WithLp.equiv 2 _ _).symm ![x, y, ...]`, of type `EuclideanSpace _ (Fin _)`. + +This also works for other subscripts. -/ +syntax (name := PiLp.vecNotation) "!" noWs subscript(term) noWs "[" term,* "]" : term +macro_rules | `(!$p:subscript[$e:term,*]) => do + -- override the `Fin n.succ` to a literal + let n := e.getElems.size + `((WithLp.equiv $p <| ∀ _ : Fin $(quote n), _).symm ![$e,*]) + +set_option trace.debug true in +/-- Unexpander for the `!₂[x, y, ...]` notation. -/ +@[delab app.DFunLike.coe] +def EuclideanSpace.delabVecNotation : Delab := + whenNotPPOption getPPExplicit <| whenPPOption getPPNotation <| withOverApp 6 do + -- check that the `(WithLp.equiv _ _).symm` is present + let p : Term ← withAppFn <| withAppArg do + let_expr Equiv.symm _ _ e := ← getExpr | failure + let_expr WithLp.equiv _ _ := e | failure + withNaryArg 2 <| withNaryArg 0 <| delab + -- to be conservative, only allow subscripts which are numerals + guard <| p matches `($_:num) + let `(![$elems,*]) := ← withAppArg delab | failure + `(!$p[$elems,*]) + +end Notation + theorem EuclideanSpace.nnnorm_eq {𝕜 : Type*} [RCLike 𝕜] {n : Type*} [Fintype n] (x : EuclideanSpace 𝕜 n) : ‖x‖₊ = NNReal.sqrt (∑ i, ‖x i‖₊ ^ 2) := PiLp.nnnorm_eq_of_L2 x @@ -891,7 +926,8 @@ noncomputable def LinearIsometry.extend (L : S →ₗᵢ[𝕜] V) : V →ₗᵢ[ calc finrank 𝕜 LSᗮ = finrank 𝕜 V - finrank 𝕜 LS := by simp only [← LS.finrank_add_finrank_orthogonal, add_tsub_cancel_left] - _ = finrank 𝕜 V - finrank 𝕜 S := by simp only [LinearMap.finrank_range_of_inj L.injective] + _ = finrank 𝕜 V - finrank 𝕜 S := by + simp only [LS, LinearMap.finrank_range_of_inj L.injective] _ = finrank 𝕜 Sᗮ := by simp only [← S.finrank_add_finrank_orthogonal, add_tsub_cancel_left] exact @@ -917,8 +953,8 @@ noncomputable def LinearIsometry.extend (L : S →ₗᵢ[𝕜] V) : V →ₗᵢ[ have Lp1x : L (p1 x) ∈ LinearMap.range L.toLinearMap := LinearMap.mem_range_self L.toLinearMap (p1 x) have Lp2x : L3 (p2 x) ∈ (LinearMap.range L.toLinearMap)ᗮ := by - simp only [LinearIsometry.coe_comp, Function.comp_apply, Submodule.coe_subtypeₗᵢ, ← - Submodule.range_subtype LSᗮ] + simp only [LinearIsometry.coe_comp, Function.comp_apply, Submodule.coe_subtypeₗᵢ, + ← Submodule.range_subtype LSᗮ] apply LinearMap.mem_range_self apply Submodule.inner_right_of_mem_orthogonal Lp1x Lp2x -- Apply the Pythagorean theorem and simplify diff --git a/Mathlib/Analysis/InnerProductSpace/Projection.lean b/Mathlib/Analysis/InnerProductSpace/Projection.lean index 6be13bb9ce5f1..902821ff1cdfd 100644 --- a/Mathlib/Analysis/InnerProductSpace/Projection.lean +++ b/Mathlib/Analysis/InnerProductSpace/Projection.lean @@ -1314,7 +1314,7 @@ theorem maximal_orthonormal_iff_orthogonalComplement_eq_bot (hv : Orthonormal rintro ⟨x, hx', hx⟩ -- take a nonzero vector and normalize it let e := (‖x‖⁻¹ : 𝕜) • x - have he : ‖e‖ = 1 := by simp [norm_smul_inv_norm hx] + have he : ‖e‖ = 1 := by simp [e, norm_smul_inv_norm hx] have he' : e ∈ (span 𝕜 v)ᗮ := smul_mem' _ _ hx' have he'' : e ∉ v := by intro hev diff --git a/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean b/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean index a3620202f0233..ce57eea606617 100644 --- a/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean +++ b/Mathlib/Analysis/InnerProductSpace/Rayleigh.lean @@ -8,6 +8,7 @@ import Mathlib.Analysis.InnerProductSpace.Dual import Mathlib.Analysis.InnerProductSpace.Adjoint import Mathlib.Analysis.Calculus.LagrangeMultipliers import Mathlib.LinearAlgebra.Eigenspace.Basic +import Mathlib.Algebra.EuclideanDomain.Basic /-! # The Rayleigh quotient diff --git a/Mathlib/Analysis/LocallyConvex/Polar.lean b/Mathlib/Analysis/LocallyConvex/Polar.lean index dba80d95bd857..af5dc28df843c 100644 --- a/Mathlib/Analysis/LocallyConvex/Polar.lean +++ b/Mathlib/Analysis/LocallyConvex/Polar.lean @@ -34,7 +34,6 @@ any bilinear form `B : E →ₗ[𝕜] F →ₗ[𝕜] 𝕜`, where `𝕜` is a no polar -/ - variable {𝕜 E F : Type*} open Topology diff --git a/Mathlib/Analysis/MeanInequalities.lean b/Mathlib/Analysis/MeanInequalities.lean index 35b6c3d8d8508..ae574c56e55c6 100644 --- a/Mathlib/Analysis/MeanInequalities.lean +++ b/Mathlib/Analysis/MeanInequalities.lean @@ -135,7 +135,7 @@ theorem geom_mean_le_arith_mean_weighted (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 -- for `exp` and numbers `log (z i)` with weights `w i`. · simp only [not_exists, not_and, Ne, Classical.not_not] at A have := convexOn_exp.map_sum_le hw hw' fun i _ => Set.mem_univ <| log (z i) - simp only [exp_sum, (· ∘ ·), smul_eq_mul, mul_comm (w _) (log _)] at this + simp only [exp_sum, smul_eq_mul, mul_comm (w _) (log _)] at this convert this using 1 <;> [apply prod_congr rfl;apply sum_congr rfl] <;> intro i hi · cases' eq_or_lt_of_le (hz i hi) with hz hz · simp [A i hi hz.symm] @@ -144,7 +144,7 @@ theorem geom_mean_le_arith_mean_weighted (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 · simp [A i hi hz.symm] · rw [exp_log hz] -/-- **AM-GM inequality**: The **geometric mean is less than or equal to the arithmetic mean. --/ +/-- **AM-GM inequality**: The **geometric mean is less than or equal to the arithmetic mean. -/ theorem geom_mean_le_arith_mean {ι : Type*} (s : Finset ι) (w : ι → ℝ) (z : ι → ℝ) (hw : ∀ i ∈ s, 0 ≤ w i) (hw' : 0 < ∑ i ∈ s, w i) (hz : ∀ i ∈ s, 0 ≤ z i) : (∏ i ∈ s, z i ^ w i) ^ (∑ i ∈ s, w i)⁻¹ ≤ (∑ i ∈ s, w i * z i) / (∑ i ∈ s, w i) := by @@ -190,6 +190,82 @@ theorem geom_mean_eq_arith_mean_weighted_of_constant (w z : ι → ℝ) (x : ℝ ∏ i ∈ s, z i ^ w i = ∑ i ∈ s, w i * z i := by rw [geom_mean_weighted_of_constant, arith_mean_weighted_of_constant] <;> assumption +/-- **AM-GM inequality - equality condition**: This theorem provides the equality condition for the +*positive* weighted version of the AM-GM inequality for real-valued nonnegative functions. -/ +theorem geom_mean_eq_arith_mean_weighted_iff' (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 < w i) + (hw' : ∑ i ∈ s, w i = 1) (hz : ∀ i ∈ s, 0 ≤ z i) : + ∏ i ∈ s, z i ^ w i = ∑ i ∈ s, w i * z i ↔ ∀ j ∈ s, z j = ∑ i ∈ s, w i * z i := by + by_cases A : ∃ i ∈ s, z i = 0 ∧ w i ≠ 0 + · rcases A with ⟨i, his, hzi, hwi⟩ + rw [prod_eq_zero his] + · constructor + · intro h + rw [← h] + intro j hj + apply eq_zero_of_ne_zero_of_mul_left_eq_zero (ne_of_lt (hw j hj)).symm + apply (sum_eq_zero_iff_of_nonneg ?_).mp h.symm j hj + exact fun i hi => (mul_nonneg_iff_of_pos_left (hw i hi)).mpr (hz i hi) + · intro h + convert h i his + exact hzi.symm + · rw [hzi] + exact zero_rpow hwi + · simp only [not_exists, not_and] at A + have hz' := fun i h => lt_of_le_of_ne (hz i h) (fun a => (A i h a.symm) (ne_of_gt (hw i h))) + have := strictConvexOn_exp.map_sum_eq_iff hw hw' fun i _ => Set.mem_univ <| log (z i) + simp only [exp_sum, smul_eq_mul, mul_comm (w _) (log _)] at this + convert this using 1 + · apply Eq.congr <;> + [apply prod_congr rfl; apply sum_congr rfl] <;> + intro i hi <;> + simp only [exp_mul, exp_log (hz' i hi)] + · constructor <;> intro h j hj + · rw [← arith_mean_weighted_of_constant s w _ (log (z j)) hw' fun i _ => congrFun rfl] + apply sum_congr rfl + intro x hx + simp only [mul_comm, h j hj, h x hx] + · rw [← arith_mean_weighted_of_constant s w _ (z j) hw' fun i _ => congrFun rfl] + apply sum_congr rfl + intro x hx + simp only [log_injOn_pos (hz' j hj) (hz' x hx), h j hj, h x hx] + +/-- **AM-GM inequality - equality condition**: This theorem provides the equality condition for the +weighted version of the AM-GM inequality for real-valued nonnegative functions. -/ +theorem geom_mean_eq_arith_mean_weighted_iff (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 ≤ w i) + (hw' : ∑ i ∈ s, w i = 1) (hz : ∀ i ∈ s, 0 ≤ z i) : + ∏ i ∈ s, z i ^ w i = ∑ i ∈ s, w i * z i ↔ ∀ j ∈ s, w j ≠ 0 → z j = ∑ i ∈ s, w i * z i := by + have h (i) (_ : i ∈ s) : w i * z i ≠ 0 → w i ≠ 0 := by apply left_ne_zero_of_mul + have h' (i) (_ : i ∈ s) : z i ^ w i ≠ 1 → w i ≠ 0 := by + by_contra! + obtain ⟨h1, h2⟩ := this + simp only [h2, rpow_zero, ne_self_iff_false] at h1 + rw [← sum_filter_of_ne h, ← prod_filter_of_ne h', geom_mean_eq_arith_mean_weighted_iff'] + · simp + · simp +contextual [(hw _ _).gt_iff_ne] + · rwa [sum_filter_ne_zero] + · simp_all only [ne_eq, mul_eq_zero, not_or, not_false_eq_true, and_imp, implies_true, mem_filter] + +/-- **AM-GM inequality - strict inequality condition**: This theorem provides the strict inequality +condition for the *positive* weighted version of the AM-GM inequality for real-valued nonnegative +functions. -/ +theorem geom_mean_lt_arith_mean_weighted_iff_of_pos (w z : ι → ℝ) (hw : ∀ i ∈ s, 0 < w i) + (hw' : ∑ i ∈ s, w i = 1) (hz : ∀ i ∈ s, 0 ≤ z i) : + ∏ i ∈ s, z i ^ w i < ∑ i ∈ s, w i * z i ↔ ∃ j ∈ s, ∃ k ∈ s, z j ≠ z k:= by + constructor + · intro h + by_contra! h_contra + rw [(geom_mean_eq_arith_mean_weighted_iff' s w z hw hw' hz).mpr ?_] at h + · exact (lt_self_iff_false _).mp h + · intro j hjs + rw [← arith_mean_weighted_of_constant s w (fun _ => z j) (z j) hw' fun _ _ => congrFun rfl] + apply sum_congr rfl (fun x a => congrArg (HMul.hMul (w x)) (h_contra j hjs x a)) + · rintro ⟨j, hjs, k, hks, hzjk⟩ + have := geom_mean_le_arith_mean_weighted s w z (fun i a => le_of_lt (hw i a)) hw' hz + by_contra! h + apply le_antisymm this at h + apply (geom_mean_eq_arith_mean_weighted_iff' s w z hw hw' hz).mp at h + simp only [h j hjs, h k hks, ne_eq, not_true_eq_false] at hzjk + end Real namespace NNReal @@ -282,7 +358,7 @@ theorem harm_mean_le_geom_mean_weighted (w z : ι → ℝ) (hs : s.Nonempty) (hw · rw [Real.inv_rpow]; apply fun i hi ↦ le_of_lt (hz i hi); assumption -/-- **HM-GM inequality**: The **harmonic mean is less than or equal to the geometric mean. --/ +/-- **HM-GM inequality**: The **harmonic mean is less than or equal to the geometric mean. -/ theorem harm_mean_le_geom_mean {ι : Type*} (s : Finset ι) (hs : s.Nonempty) (w : ι → ℝ) (z : ι → ℝ) (hw : ∀ i ∈ s, 0 < w i) (hw' : 0 < ∑ i in s, w i) (hz : ∀ i ∈ s, 0 < z i) : (∑ i in s, w i) / (∑ i in s, w i / z i) ≤ (∏ i in s, z i ^ w i) ^ (∑ i in s, w i)⁻¹ := by diff --git a/Mathlib/Analysis/Normed/Affine/Isometry.lean b/Mathlib/Analysis/Normed/Affine/Isometry.lean index d6db878a74fdd..ad879f1396054 100644 --- a/Mathlib/Analysis/Normed/Affine/Isometry.lean +++ b/Mathlib/Analysis/Normed/Affine/Isometry.lean @@ -650,7 +650,7 @@ def pointReflection (x : P) : P ≃ᵃⁱ[𝕜] P := variable {𝕜} -theorem pointReflection_apply (x y : P) : (pointReflection 𝕜 x) y = x -ᵥ y +ᵥ x := +theorem pointReflection_apply (x y : P) : (pointReflection 𝕜 x) y = (x -ᵥ y) +ᵥ x := rfl @[simp] diff --git a/Mathlib/Analysis/Normed/Field/Basic.lean b/Mathlib/Analysis/Normed/Field/Basic.lean index 00424d49f8973..d730d9d8baf82 100644 --- a/Mathlib/Analysis/Normed/Field/Basic.lean +++ b/Mathlib/Analysis/Normed/Field/Basic.lean @@ -9,6 +9,7 @@ import Mathlib.Algebra.Field.Subfield.Defs import Mathlib.Algebra.Order.Group.Pointwise.Interval import Mathlib.Analysis.Normed.Group.Constructions import Mathlib.Analysis.Normed.Group.Submodule +import Mathlib.Algebra.Ring.Regular /-! # Normed fields diff --git a/Mathlib/Analysis/Normed/Group/ControlledClosure.lean b/Mathlib/Analysis/Normed/Group/ControlledClosure.lean index 2a79581ba1dcc..62167b8250217 100644 --- a/Mathlib/Analysis/Normed/Group/ControlledClosure.lean +++ b/Mathlib/Analysis/Normed/Group/ControlledClosure.lean @@ -59,7 +59,7 @@ theorem controlled_closure_of_complete {f : NormedAddGroupHom G H} {K : AddSubgr calc ‖u n‖ ≤ C * ‖v n‖ := hnorm_u n _ ≤ C * b n := by gcongr; exact (hv _ <| Nat.succ_le_iff.mp hn).le - _ = (1 / 2) ^ n * (ε * ‖h‖ / 2) := by simp [mul_div_cancel₀ _ hC.ne.symm] + _ = (1 / 2) ^ n * (ε * ‖h‖ / 2) := by simp [b, mul_div_cancel₀ _ hC.ne.symm] _ = ε * ‖h‖ / 2 * (1 / 2) ^ n := mul_comm _ _ -- We now show that the limit `g` of `s` is the desired preimage. obtain ⟨g : G, hg⟩ := cauchySeq_tendsto_of_complete this @@ -89,7 +89,7 @@ theorem controlled_closure_of_complete {f : NormedAddGroupHom G H} {K : AddSubgr have : (∑ k ∈ range (n + 1), C * b k) ≤ ε * ‖h‖ := calc (∑ k ∈ range (n + 1), C * b k) _ = (∑ k ∈ range (n + 1), (1 / 2 : ℝ) ^ k) * (ε * ‖h‖ / 2) := by - simp only [mul_div_cancel₀ _ hC.ne.symm, ← sum_mul] + simp only [b, mul_div_cancel₀ _ hC.ne.symm, ← sum_mul] _ ≤ 2 * (ε * ‖h‖ / 2) := by gcongr; apply sum_geometric_two_le _ = ε * ‖h‖ := mul_div_cancel₀ _ two_ne_zero calc diff --git a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean index 6635a5d5fb355..d77bc7fea6e3e 100644 --- a/Mathlib/Analysis/Normed/Lp/LpEquiv.lean +++ b/Mathlib/Analysis/Normed/Lp/LpEquiv.lean @@ -91,9 +91,6 @@ section Equivₗᵢ variable [Fintype α] (𝕜 : Type*) [NontriviallyNormedField 𝕜] [∀ i, NormedSpace 𝕜 (E i)] variable (E) -/- porting note: Lean is unable to work with `lpPiLpₗᵢ` if `E` is implicit without -annotating with `(E := E)` everywhere, so we just make it explicit. This file has no -dependencies. -/ /-- The canonical `LinearIsometryEquiv` between `lp E p` and `PiLp p E` when `E : α → Type u` with `[Fintype α]` and `[Fact (1 ≤ p)]`. -/ @@ -145,9 +142,6 @@ theorem coe_addEquiv_lpBCF_symm (f : α →ᵇ E) : (AddEquiv.lpBCF.symm f : α rfl variable (E) -/- porting note: Lean is unable to work with `lpPiLpₗᵢ` if `E` is implicit without -annotating with `(E := E)` everywhere, so we just make it explicit. This file has no -dependencies. -/ /-- The canonical map between `lp (fun _ : α ↦ E) ∞` and `α →ᵇ E` as a `LinearIsometryEquiv`. -/ noncomputable def lpBCFₗᵢ : lp (fun _ : α ↦ E) ∞ ≃ₗᵢ[𝕜] α →ᵇ E := diff --git a/Mathlib/Analysis/Normed/Operator/Banach.lean b/Mathlib/Analysis/Normed/Operator/Banach.lean index 8810020324216..27ca8d21c6ddf 100644 --- a/Mathlib/Analysis/Normed/Operator/Banach.lean +++ b/Mathlib/Analysis/Normed/Operator/Banach.lean @@ -121,7 +121,7 @@ theorem exists_approx_preimage_norm_le (surj : Surjective f) : calc ‖f x - d • y‖ = ‖f x₁ - (a + d • y) - (f x₂ - a)‖ := by congr 1 - simp only [f.map_sub] + simp only [x, f.map_sub] abel _ ≤ ‖f x₁ - (a + d • y)‖ + ‖f x₂ - a‖ := norm_sub_le _ _ _ ≤ δ + δ := by rw [dist_eq_norm'] at h₁ h₂; gcongr diff --git a/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean b/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean index 33d288c85a3c2..9ad44b68f8091 100644 --- a/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean +++ b/Mathlib/Analysis/Normed/Operator/BoundedLinearMaps.lean @@ -190,15 +190,22 @@ theorem isBoundedLinearMap_prod_multilinear {E : ι → Type*} [∀ i, Seminorme [∀ i, NormedSpace 𝕜 (E i)] : IsBoundedLinearMap 𝕜 fun p : ContinuousMultilinearMap 𝕜 E F × ContinuousMultilinearMap 𝕜 E G => p.1.prod p.2 := - (ContinuousMultilinearMap.prodL ..).toContinuousLinearEquiv + (ContinuousMultilinearMap.prodL 𝕜 E F G).toContinuousLinearEquiv |>.toContinuousLinearMap.isBoundedLinearMap +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6024 +we needed to add the named arguments `(ι := ι) (G := F)` +to `ContinuousMultilinearMap.compContinuousLinearMapL`. +-/ /-- Given a fixed continuous linear map `g`, associating to a continuous multilinear map `f` the continuous multilinear map `f (g m₁, ..., g mₙ)` is a bounded linear operation. -/ theorem isBoundedLinearMap_continuousMultilinearMap_comp_linear (g : G →L[𝕜] E) : IsBoundedLinearMap 𝕜 fun f : ContinuousMultilinearMap 𝕜 (fun _ : ι => E) F => f.compContinuousLinearMap fun _ => g := - (ContinuousMultilinearMap.compContinuousLinearMapL fun _ ↦ g).isBoundedLinearMap + (ContinuousMultilinearMap.compContinuousLinearMapL (ι := ι) (G := F) (fun _ ↦ g)) + |>.isBoundedLinearMap end diff --git a/Mathlib/Analysis/Normed/Ring/WithAbs.lean b/Mathlib/Analysis/Normed/Ring/WithAbs.lean index d616c2ef77867..4cbcad5fc3e00 100644 --- a/Mathlib/Analysis/Normed/Ring/WithAbs.lean +++ b/Mathlib/Analysis/Normed/Ring/WithAbs.lean @@ -22,7 +22,7 @@ being used to define Archimedean completions of a number field. to assign and infer instances on a semiring that depend on absolute values. - `WithAbs.equiv v` : the canonical (type) equivalence between `WithAbs v` and `R`. - `WithAbs.ringEquiv v` : The canonical ring equivalence between `WithAbs v` and `R`. - - `AbsoluteValue.completion` : the uniform space completion of a field `K` according to the + - `AbsoluteValue.Completion` : the uniform space completion of a field `K` according to the uniform structure defined by the specified real absolute value. -/ @@ -141,18 +141,20 @@ open WithAbs variable {K : Type*} [Field K] (v : AbsoluteValue K ℝ) /-- The completion of a field with respect to a real absolute value. -/ -abbrev completion := UniformSpace.Completion (WithAbs v) +abbrev Completion := UniformSpace.Completion (WithAbs v) + +@[deprecated (since := "2024-12-01")] alias completion := Completion namespace Completion -instance : Coe K v.completion := +instance : Coe K v.Completion := inferInstanceAs <| Coe (WithAbs v) (UniformSpace.Completion (WithAbs v)) variable {L : Type*} [NormedField L] [CompleteSpace L] {f : WithAbs v →+* L} {v} /-- If the absolute value of a normed field factors through an embedding into another normed field -`L`, then we can extend that embedding to an embedding on the completion `v.completion →+* L`. -/ -abbrev extensionEmbedding_of_comp (h : ∀ x, ‖f x‖ = v x) : v.completion →+* L := +`L`, then we can extend that embedding to an embedding on the completion `v.Completion →+* L`. -/ +abbrev extensionEmbedding_of_comp (h : ∀ x, ‖f x‖ = v x) : v.Completion →+* L := UniformSpace.Completion.extensionHom _ (WithAbs.isUniformInducing_of_comp h).uniformContinuous.continuous @@ -162,8 +164,8 @@ theorem extensionEmbedding_of_comp_coe (h : ∀ x, ‖f x‖ = v x) (x : K) : (WithAbs.isUniformInducing_of_comp h).uniformContinuous.continuous] /-- If the absolute value of a normed field factors through an embedding into another normed field, -then the extended embedding `v.completion →+* L` preserves distances. -/ -theorem extensionEmbedding_dist_eq_of_comp (h : ∀ x, ‖f x‖ = v x) (x y : v.completion) : +then the extended embedding `v.Completion →+* L` preserves distances. -/ +theorem extensionEmbedding_dist_eq_of_comp (h : ∀ x, ‖f x‖ = v x) (x y : v.Completion) : dist (extensionEmbedding_of_comp h x) (extensionEmbedding_of_comp h y) = dist x y := by refine UniformSpace.Completion.induction_on₂ x y ?_ (fun x y => ?_) @@ -173,13 +175,13 @@ theorem extensionEmbedding_dist_eq_of_comp (h : ∀ x, ‖f x‖ = v x) (x y : v exact UniformSpace.Completion.dist_eq x y ▸ (WithAbs.isometry_of_comp h).dist_eq _ _ /-- If the absolute value of a normed field factors through an embedding into another normed field, -then the extended embedding `v.completion →+* L` is an isometry. -/ +then the extended embedding `v.Completion →+* L` is an isometry. -/ theorem isometry_extensionEmbedding_of_comp (h : ∀ x, ‖f x‖ = v x) : Isometry (extensionEmbedding_of_comp h) := Isometry.of_dist_eq <| extensionEmbedding_dist_eq_of_comp h /-- If the absolute value of a normed field factors through an embedding into another normed field, -then the extended embedding `v.completion →+* L` is a closed embedding. -/ +then the extended embedding `v.Completion →+* L` is a closed embedding. -/ theorem isClosedEmbedding_extensionEmbedding_of_comp (h : ∀ x, ‖f x‖ = v x) : IsClosedEmbedding (extensionEmbedding_of_comp h) := (isometry_extensionEmbedding_of_comp h).isClosedEmbedding @@ -187,7 +189,7 @@ theorem isClosedEmbedding_extensionEmbedding_of_comp (h : ∀ x, ‖f x‖ = v x /-- If the absolute value of a normed field factors through an embedding into another normed field that is locally compact, then the completion of the first normed field is also locally compact. -/ theorem locallyCompactSpace [LocallyCompactSpace L] (h : ∀ x, ‖f x‖ = v x) : - LocallyCompactSpace (v.completion) := + LocallyCompactSpace (v.Completion) := (isClosedEmbedding_extensionEmbedding_of_comp h).locallyCompactSpace end AbsoluteValue.Completion diff --git a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean index 7684f1deeb4fc..ed0229bf183df 100644 --- a/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean +++ b/Mathlib/Analysis/NormedSpace/HahnBanach/SeparatingDual.lean @@ -5,8 +5,9 @@ Authors: Sébastien Gouëzel -/ import Mathlib.Analysis.NormedSpace.HahnBanach.Extension import Mathlib.Analysis.NormedSpace.HahnBanach.Separation +import Mathlib.Analysis.NormedSpace.Multilinear.Basic +import Mathlib.Analysis.NormedSpace.OperatorNorm.Completeness import Mathlib.LinearAlgebra.Dual -import Mathlib.Analysis.Normed.Operator.BoundedLinearMaps /-! # Spaces with separating dual diff --git a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean index 9ebb2a8c9c154..ca6f026c41a7c 100644 --- a/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean +++ b/Mathlib/Analysis/NormedSpace/Multilinear/Basic.lean @@ -541,7 +541,7 @@ search. -/ instance normedSpace' : NormedSpace 𝕜' (ContinuousMultilinearMap 𝕜 (fun _ : ι => G') G) := ContinuousMultilinearMap.normedSpace -@[deprecated (since := "2024-11-24")] +@[deprecated norm_neg (since := "2024-11-24")] theorem opNorm_neg (f : ContinuousMultilinearMap 𝕜 E G) : ‖-f‖ = ‖f‖ := norm_neg f @[deprecated (since := "2024-02-02")] alias op_norm_neg := norm_neg @@ -672,8 +672,8 @@ def prodL : @[simps! apply symm_apply] def piₗᵢ {ι' : Type v'} [Fintype ι'] {E' : ι' → Type wE'} [∀ i', NormedAddCommGroup (E' i')] [∀ i', NormedSpace 𝕜 (E' i')] : - (∀ i', ContinuousMultilinearMap 𝕜 E (E' i')) ≃ₗᵢ[𝕜] - ContinuousMultilinearMap 𝕜 E (∀ i, E' i) where + (Π i', ContinuousMultilinearMap 𝕜 E (E' i')) + ≃ₗᵢ[𝕜] (ContinuousMultilinearMap 𝕜 E (Π i, E' i)) where toLinearEquiv := piLinearEquiv norm_map' := opNorm_pi diff --git a/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean index 61f5199b50531..6b959b42931e5 100644 --- a/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean +++ b/Mathlib/Analysis/NormedSpace/OperatorNorm/Bilinear.lean @@ -460,3 +460,36 @@ theorem norm_smulRightL_apply (c : E →L[𝕜] 𝕜) (f : Fₗ) : ‖smulRightL end ContinuousLinearMap end SemiNormed + +section Restrict + +namespace ContinuousLinearMap + +variable {𝕜' : Type*} [NontriviallyNormedField 𝕜] [NontriviallyNormedField 𝕜'] [NormedAlgebra 𝕜 𝕜'] + [SeminormedAddCommGroup E] [NormedSpace 𝕜 E] [NormedSpace 𝕜' E] [IsScalarTower 𝕜 𝕜' E] + [SeminormedAddCommGroup F] [NormedSpace 𝕜 F] [NormedSpace 𝕜' F] [IsScalarTower 𝕜 𝕜' F] + [SeminormedAddCommGroup G] [NormedSpace 𝕜 G] [NormedSpace 𝕜' G] [IsScalarTower 𝕜 𝕜' G] + +variable (𝕜) in +/-- Convenience function for restricting the linearity of a bilinear map. -/ +def bilinearRestrictScalars (B : E →L[𝕜'] F →L[𝕜'] G) : E →L[𝕜] F →L[𝕜] G := + (restrictScalarsL 𝕜' F G 𝕜 𝕜).comp (B.restrictScalars 𝕜) + +variable (B : E →L[𝕜'] F →L[𝕜'] G) (x : E) (y : F) + +theorem bilinearRestrictScalars_eq_restrictScalarsL_comp_restrictScalars : + B.bilinearRestrictScalars 𝕜 = (restrictScalarsL 𝕜' F G 𝕜 𝕜).comp (B.restrictScalars 𝕜) := rfl + +theorem bilinearRestrictScalars_eq_restrictScalars_restrictScalarsL_comp : + B.bilinearRestrictScalars 𝕜 = restrictScalars 𝕜 ((restrictScalarsL 𝕜' F G 𝕜 𝕜').comp B) := rfl + +variable (𝕜) in +@[simp] +theorem bilinearRestrictScalars_apply_apply : (B.bilinearRestrictScalars 𝕜) x y = B x y := rfl + +@[simp] +theorem norm_bilinearRestrictScalars : ‖B.bilinearRestrictScalars 𝕜‖ = ‖B‖ := rfl + +end ContinuousLinearMap + +end Restrict diff --git a/Mathlib/Analysis/NormedSpace/RieszLemma.lean b/Mathlib/Analysis/NormedSpace/RieszLemma.lean index 553d89feaaa42..1fc30104864f2 100644 --- a/Mathlib/Analysis/NormedSpace/RieszLemma.lean +++ b/Mathlib/Analysis/NormedSpace/RieszLemma.lean @@ -98,7 +98,7 @@ theorem riesz_lemma_of_norm_lt {c : 𝕜} (hc : 1 < ‖c‖) {R : ℝ} (hR : ‖ _ = ‖d‖ * (‖c‖ / R * ‖x‖) := by simp only [norm_smul] ring - _ ≤ ‖d‖ * ‖x - y'‖ := by gcongr; exact hx y' (by simp [Submodule.smul_mem _ _ hy]) + _ ≤ ‖d‖ * ‖x - y'‖ := by gcongr; exact hx y' (by simp [y', Submodule.smul_mem _ _ hy]) _ = ‖d • x - y‖ := by rw [yy', ← smul_sub, norm_smul] theorem Metric.closedBall_infDist_compl_subset_closure {x : F} {s : Set F} (hx : x ∈ s) : diff --git a/Mathlib/Analysis/ODE/Gronwall.lean b/Mathlib/Analysis/ODE/Gronwall.lean index dd27e37df8326..011ee6ec7c7d1 100644 --- a/Mathlib/Analysis/ODE/Gronwall.lean +++ b/Mathlib/Analysis/ODE/Gronwall.lean @@ -127,9 +127,7 @@ theorem norm_le_gronwallBound_of_norm_deriv_right_le {f f' : ℝ → E} {δ K ε (fun x hx _r hr => (hf' x hx).liminf_right_slope_norm_le hr) ha bound variable {v : ℝ → E → E} {s : ℝ → Set E} {K : ℝ≥0} {f g f' g' : ℝ → E} {a b t₀ : ℝ} {εf εg δ : ℝ} - (hv : ∀ t, LipschitzOnWith K (v t) (s t)) -include hv in /-- If `f` and `g` are two approximate solutions of the same ODE, then the distance between them can't grow faster than exponentially. This is a simple corollary of Grönwall's inequality, and some people call this Grönwall's inequality too. @@ -137,6 +135,7 @@ people call this Grönwall's inequality too. This version assumes all inequalities to be true in some time-dependent set `s t`, and assumes that the solutions never leave this set. -/ theorem dist_le_of_approx_trajectories_ODE_of_mem + (hv : ∀ t ∈ Ico a b, LipschitzOnWith K (v t) (s t)) (hf : ContinuousOn f (Icc a b)) (hf' : ∀ t ∈ Ico a b, HasDerivWithinAt f (f' t) (Ici t) t) (f_bound : ∀ t ∈ Ico a b, dist (f' t) (v t (f t)) ≤ εf) @@ -153,7 +152,7 @@ theorem dist_le_of_approx_trajectories_ODE_of_mem apply norm_le_gronwallBound_of_norm_deriv_right_le (hf.sub hg) h_deriv ha intro t ht have := dist_triangle4_right (f' t) (g' t) (v t (f t)) (v t (g t)) - have hv := (hv t).dist_le_mul _ (hfs t ht) _ (hgs t ht) + have hv := (hv t ht).dist_le_mul _ (hfs t ht) _ (hgs t ht) rw [← dist_eq_norm, ← dist_eq_norm] refine this.trans ((add_le_add (add_le_add (f_bound t ht) (g_bound t ht)) hv).trans ?_) rw [add_comm] @@ -174,10 +173,9 @@ theorem dist_le_of_approx_trajectories_ODE (ha : dist (f a) (g a) ≤ δ) : ∀ t ∈ Icc a b, dist (f t) (g t) ≤ gronwallBound δ K (εf + εg) (t - a) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - dist_le_of_approx_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith) hf hf' + dist_le_of_approx_trajectories_ODE_of_mem (fun t _ => (hv t).lipschitzOnWith) hf hf' f_bound hfs hg hg' g_bound (fun _ _ => trivial) ha -include hv in /-- If `f` and `g` are two exact solutions of the same ODE, then the distance between them can't grow faster than exponentially. This is a simple corollary of Grönwall's inequality, and some people call this Grönwall's inequality too. @@ -185,6 +183,7 @@ people call this Grönwall's inequality too. This version assumes all inequalities to be true in some time-dependent set `s t`, and assumes that the solutions never leave this set. -/ theorem dist_le_of_trajectories_ODE_of_mem + (hv : ∀ t ∈ Ico a b, LipschitzOnWith K (v t) (s t)) (hf : ContinuousOn f (Icc a b)) (hf' : ∀ t ∈ Ico a b, HasDerivWithinAt f (v t (f t)) (Ici t) t) (hfs : ∀ t ∈ Ico a b, f t ∈ s t) @@ -212,16 +211,16 @@ theorem dist_le_of_trajectories_ODE (ha : dist (f a) (g a) ≤ δ) : ∀ t ∈ Icc a b, dist (f t) (g t) ≤ δ * exp (K * (t - a)) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - dist_le_of_trajectories_ODE_of_mem (fun t => (hv t).lipschitzOnWith) hf hf' hfs hg + dist_le_of_trajectories_ODE_of_mem (fun t _ => (hv t).lipschitzOnWith) hf hf' hfs hg hg' (fun _ _ => trivial) ha -include hv in /-- There exists only one solution of an ODE \(\dot x=v(t, x)\) in a set `s ⊆ ℝ × E` with a given initial value provided that the RHS is Lipschitz continuous in `x` within `s`, and we consider only solutions included in `s`. This version shows uniqueness in a closed interval `Icc a b`, where `a` is the initial time. -/ theorem ODE_solution_unique_of_mem_Icc_right + (hv : ∀ t ∈ Ico a b, LipschitzOnWith K (v t) (s t)) (hf : ContinuousOn f (Icc a b)) (hf' : ∀ t ∈ Ico a b, HasDerivWithinAt f (v t (f t)) (Ici t) t) (hfs : ∀ t ∈ Ico a b, f t ∈ s t) @@ -233,10 +232,10 @@ theorem ODE_solution_unique_of_mem_Icc_right have := dist_le_of_trajectories_ODE_of_mem hv hf hf' hfs hg hg' hgs (dist_le_zero.2 ha) t ht rwa [zero_mul, dist_le_zero] at this -include hv in /-- A time-reversed version of `ODE_solution_unique_of_mem_Icc_right`. Uniqueness is shown in a closed interval `Icc a b`, where `b` is the "initial" time. -/ theorem ODE_solution_unique_of_mem_Icc_left + (hv : ∀ t ∈ Ioc a b, LipschitzOnWith K (v t) (s t)) (hf : ContinuousOn f (Icc a b)) (hf' : ∀ t ∈ Ioc a b, HasDerivWithinAt f (v t (f t)) (Iic t) t) (hfs : ∀ t ∈ Ioc a b, f t ∈ s t) @@ -245,9 +244,13 @@ theorem ODE_solution_unique_of_mem_Icc_left (hgs : ∀ t ∈ Ioc a b, g t ∈ s t) (hb : f b = g b) : EqOn f g (Icc a b) := by - have hv' t : LipschitzOnWith K (Neg.neg ∘ (v (-t))) (s (-t)) := by + have hv' : ∀ t ∈ Ico (-b) (-a), LipschitzOnWith K (Neg.neg ∘ (v (-t))) (s (-t)) := by + intro t ht + replace ht : -t ∈ Ioc a b := by + simp at ht ⊢ + constructor <;> linarith rw [← one_mul K] - exact LipschitzWith.id.neg.comp_lipschitzOnWith (hv _) + exact LipschitzWith.id.neg.comp_lipschitzOnWith (hv _ ht) have hmt1 : MapsTo Neg.neg (Icc (-b) (-a)) (Icc a b) := fun _ ht ↦ ⟨le_neg.mp ht.2, neg_le.mp ht.1⟩ have hmt2 : MapsTo Neg.neg (Ico (-b) (-a)) (Ioc a b) := @@ -270,10 +273,10 @@ theorem ODE_solution_unique_of_mem_Icc_left (hasDerivAt_neg t).hasDerivWithinAt (hmt3 t) simp -include hv in /-- A version of `ODE_solution_unique_of_mem_Icc_right` for uniqueness in a closed interval whose interior contains the initial time. -/ theorem ODE_solution_unique_of_mem_Icc + (hv : ∀ t ∈ Ioo a b, LipschitzOnWith K (v t) (s t)) (ht : t₀ ∈ Ioo a b) (hf : ContinuousOn f (Icc a b)) (hf' : ∀ t ∈ Ioo a b, HasDerivAt f (v t (f t)) t) @@ -286,21 +289,21 @@ theorem ODE_solution_unique_of_mem_Icc rw [← Icc_union_Icc_eq_Icc (le_of_lt ht.1) (le_of_lt ht.2)] apply EqOn.union · have hss : Ioc a t₀ ⊆ Ioo a b := Ioc_subset_Ioo_right ht.2 - exact ODE_solution_unique_of_mem_Icc_left hv + exact ODE_solution_unique_of_mem_Icc_left (fun t ht ↦ hv t (hss ht)) (hf.mono <| Icc_subset_Icc_right <| le_of_lt ht.2) (fun _ ht' ↦ (hf' _ (hss ht')).hasDerivWithinAt) (fun _ ht' ↦ (hfs _ (hss ht'))) (hg.mono <| Icc_subset_Icc_right <| le_of_lt ht.2) (fun _ ht' ↦ (hg' _ (hss ht')).hasDerivWithinAt) (fun _ ht' ↦ (hgs _ (hss ht'))) heq · have hss : Ico t₀ b ⊆ Ioo a b := Ico_subset_Ioo_left ht.1 - exact ODE_solution_unique_of_mem_Icc_right hv + exact ODE_solution_unique_of_mem_Icc_right (fun t ht ↦ hv t (hss ht)) (hf.mono <| Icc_subset_Icc_left <| le_of_lt ht.1) (fun _ ht' ↦ (hf' _ (hss ht')).hasDerivWithinAt) (fun _ ht' ↦ (hfs _ (hss ht'))) (hg.mono <| Icc_subset_Icc_left <| le_of_lt ht.1) (fun _ ht' ↦ (hg' _ (hss ht')).hasDerivWithinAt) (fun _ ht' ↦ (hgs _ (hss ht'))) heq -include hv in /-- A version of `ODE_solution_unique_of_mem_Icc` for uniqueness in an open interval. -/ theorem ODE_solution_unique_of_mem_Ioo + (hv : ∀ t ∈ Ioo a b, LipschitzOnWith K (v t) (s t)) (ht : t₀ ∈ Ioo a b) (hf : ∀ t ∈ Ioo a b, HasDerivAt f (v t (f t)) t ∧ f t ∈ s t) (hg : ∀ t ∈ Ioo a b, HasDerivAt g (v t (g t)) t ∧ g t ∈ s t) @@ -310,7 +313,8 @@ theorem ODE_solution_unique_of_mem_Ioo rcases lt_or_le t' t₀ with (h | h) · have hss : Icc t' t₀ ⊆ Ioo a b := fun _ ht'' ↦ ⟨lt_of_lt_of_le ht'.1 ht''.1, lt_of_le_of_lt ht''.2 ht.2⟩ - exact ODE_solution_unique_of_mem_Icc_left hv + exact ODE_solution_unique_of_mem_Icc_left + (fun t'' ht'' ↦ hv t'' ((Ioc_subset_Icc_self.trans hss) ht'')) (continuousOn_of_forall_continuousAt fun _ ht'' ↦ (hf _ <| hss ht'').1.continuousAt) (fun _ ht'' ↦ (hf _ <| hss <| Ioc_subset_Icc_self ht'').1.hasDerivWithinAt) (fun _ ht'' ↦ (hf _ <| hss <| Ioc_subset_Icc_self ht'').2) @@ -320,7 +324,8 @@ theorem ODE_solution_unique_of_mem_Ioo ⟨le_rfl, le_of_lt h⟩ · have hss : Icc t₀ t' ⊆ Ioo a b := fun _ ht'' ↦ ⟨lt_of_lt_of_le ht.1 ht''.1, lt_of_le_of_lt ht''.2 ht'.2⟩ - exact ODE_solution_unique_of_mem_Icc_right hv + exact ODE_solution_unique_of_mem_Icc_right + (fun t'' ht'' ↦ hv t'' ((Ico_subset_Icc_self.trans hss) ht'')) (continuousOn_of_forall_continuousAt fun _ ht'' ↦ (hf _ <| hss ht'').1.continuousAt) (fun _ ht'' ↦ (hf _ <| hss <| Ico_subset_Icc_self ht'').1.hasDerivWithinAt) (fun _ ht'' ↦ (hf _ <| hss <| Ico_subset_Icc_self ht'').2) @@ -329,18 +334,19 @@ theorem ODE_solution_unique_of_mem_Ioo (fun _ ht'' ↦ (hg _ <| hss <| Ico_subset_Icc_self ht'').2) heq ⟨h, le_rfl⟩ -include hv in /-- Local unqueness of ODE solutions. -/ theorem ODE_solution_unique_of_eventually + (hv : ∀ᶠ t in 𝓝 t₀, LipschitzOnWith K (v t) (s t)) (hf : ∀ᶠ t in 𝓝 t₀, HasDerivAt f (v t (f t)) t ∧ f t ∈ s t) (hg : ∀ᶠ t in 𝓝 t₀, HasDerivAt g (v t (g t)) t ∧ g t ∈ s t) (heq : f t₀ = g t₀) : f =ᶠ[𝓝 t₀] g := by - obtain ⟨ε, hε, h⟩ := eventually_nhds_iff_ball.mp (hf.and hg) + obtain ⟨ε, hε, h⟩ := eventually_nhds_iff_ball.mp (hv.and (hf.and hg)) rw [Filter.eventuallyEq_iff_exists_mem] refine ⟨ball t₀ ε, ball_mem_nhds _ hε, ?_⟩ simp_rw [Real.ball_eq_Ioo] at * - apply ODE_solution_unique_of_mem_Ioo hv (Real.ball_eq_Ioo t₀ ε ▸ mem_ball_self hε) - (fun _ ht ↦ (h _ ht).1) (fun _ ht ↦ (h _ ht).2) heq + apply ODE_solution_unique_of_mem_Ioo (fun _ ht ↦ (h _ ht).1) + (Real.ball_eq_Ioo t₀ ε ▸ mem_ball_self hε) + (fun _ ht ↦ (h _ ht).2.1) (fun _ ht ↦ (h _ ht).2.2) heq /-- There exists only one solution of an ODE \(\dot x=v(t, x)\) with a given initial value provided that the RHS is Lipschitz continuous in `x`. -/ @@ -353,5 +359,5 @@ theorem ODE_solution_unique (ha : f a = g a) : EqOn f g (Icc a b) := have hfs : ∀ t ∈ Ico a b, f t ∈ @univ E := fun _ _ => trivial - ODE_solution_unique_of_mem_Icc_right (fun t => (hv t).lipschitzOnWith) hf hf' hfs hg hg' + ODE_solution_unique_of_mem_Icc_right (fun t _ => (hv t).lipschitzOnWith) hf hf' hfs hg hg' (fun _ _ => trivial) ha diff --git a/Mathlib/Analysis/Quaternion.lean b/Mathlib/Analysis/Quaternion.lean index ff600ebb0aa50..9f75be8137503 100644 --- a/Mathlib/Analysis/Quaternion.lean +++ b/Mathlib/Analysis/Quaternion.lean @@ -165,7 +165,7 @@ theorem norm_piLp_equiv_symm_equivTuple (x : ℍ) : noncomputable def linearIsometryEquivTuple : ℍ ≃ₗᵢ[ℝ] EuclideanSpace ℝ (Fin 4) := { (QuaternionAlgebra.linearEquivTuple (-1 : ℝ) (-1 : ℝ)).trans (WithLp.linearEquiv 2 ℝ (Fin 4 → ℝ)).symm with - toFun := fun a => (WithLp.equiv _ (Fin 4 → _)).symm ![a.1, a.2, a.3, a.4] + toFun := fun a => !₂[a.1, a.2, a.3, a.4] invFun := fun a => ⟨a 0, a 1, a 2, a 3⟩ norm_map' := norm_piLp_equiv_symm_equivTuple } diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean index d717114a27b82..ef1748b715e87 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/Analytic.lean @@ -62,11 +62,11 @@ theorem AnalyticAt.cpow (fa : AnalyticAt ℂ f x) (ga : AnalyticAt ℂ g x) exact fa.cpow ga m /-- `f z ^ g z` is analytic if `f z` avoids nonpositive reals -/ -theorem AnalyticOnNhd.cpow (fs : AnalyticOnNhd ℂ f s) (gs : AnalyticOnNhd ℂ g s) - (m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOnNhd ℂ (fun z ↦ f z ^ g z) s := +theorem AnalyticOn.cpow (fs : AnalyticOn ℂ f s) (gs : AnalyticOn ℂ g s) + (m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOn ℂ (fun z ↦ f z ^ g z) s := fun z n ↦ (fs z n).cpow (gs z n) (m z n) /-- `f z ^ g z` is analytic if `f z` avoids nonpositive reals -/ -theorem AnalyticOn.cpow (fs : AnalyticOn ℂ f s) (gs : AnalyticOn ℂ g s) - (m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOn ℂ (fun z ↦ f z ^ g z) s := +theorem AnalyticOnNhd.cpow (fs : AnalyticOnNhd ℂ f s) (gs : AnalyticOnNhd ℂ g s) + (m : ∀ z ∈ s, f z ∈ slitPlane) : AnalyticOnNhd ℂ (fun z ↦ f z ^ g z) s := fun z n ↦ (fs z n).cpow (gs z n) (m z n) diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean index 51294919f4f57..061caf910fee5 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogBounds.lean @@ -148,7 +148,8 @@ lemma norm_log_sub_logTaylor_le (n : ℕ) {z : ℂ} (hz : ‖z‖ < 1) : have H : f z = z * ∫ t in (0 : ℝ)..1, (-(t * z)) ^ n * (1 + t * z)⁻¹ := by convert (integral_unitInterval_deriv_eq_sub hcont hderiv).symm using 1 · simp only [f, zero_add, add_zero, log_one, logTaylor_at_zero, sub_self, sub_zero] - · simp only [add_zero, log_one, logTaylor_at_zero, sub_self, real_smul, zero_add, smul_eq_mul] + · simp only [f', add_zero, log_one, logTaylor_at_zero, sub_self, real_smul, zero_add, + smul_eq_mul] unfold f at H simp only [H, norm_mul] simp_rw [neg_pow (_ * z) n, mul_assoc, intervalIntegral.integral_const_mul, mul_pow, diff --git a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean index 464284b57e5ea..8274b1696a1db 100644 --- a/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Complex/LogDeriv.lean @@ -13,6 +13,8 @@ import Mathlib.Analysis.SpecialFunctions.ExpDeriv -/ +assert_not_exists IsConformalMap +assert_not_exists Conformal open Set Filter @@ -64,7 +66,7 @@ theorem hasStrictFDerivAt_log_real {x : ℂ} (h : x ∈ slitPlane) : HasStrictFDerivAt log (x⁻¹ • (1 : ℂ →L[ℝ] ℂ)) x := (hasStrictDerivAt_log h).complexToReal_fderiv -theorem contDiffAt_log {x : ℂ} (h : x ∈ slitPlane) {n : ℕ∞} : ContDiffAt ℂ n log x := +theorem contDiffAt_log {x : ℂ} (h : x ∈ slitPlane) {n : WithTop ℕ∞} : ContDiffAt ℂ n log x := expPartialHomeomorph.contDiffAt_symm_deriv (exp_ne_zero <| log x) h (hasDerivAt_exp _) contDiff_exp.contDiffAt diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PosPart.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PosPart.lean index 959183c53b686..b025d0d6c2621 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PosPart.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/PosPart.lean @@ -16,6 +16,10 @@ the continuous functional calculus and develops the basic API, including the uni positive and negative parts. -/ +open scoped NNReal + +section NonUnital + variable {A : Type*} [NonUnitalRing A] [Module ℝ A] [SMulCommClass ℝ A A] [IsScalarTower ℝ A A] variable [StarRing A] [TopologicalSpace A] variable [NonUnitalContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] @@ -36,6 +40,12 @@ lemma posPart_def (a : A) : a⁺ = cfcₙ (·⁺ : ℝ → ℝ) a := rfl lemma negPart_def (a : A) : a⁻ = cfcₙ (·⁻ : ℝ → ℝ) a := rfl +@[simp] +lemma posPart_zero : (0 : A)⁺ = 0 := by simp [posPart_def] + +@[simp] +lemma negPart_zero : (0 : A)⁻ = 0 := by simp [negPart_def] + @[simp] lemma posPart_mul_negPart (a : A) : a⁺ * a⁻ = 0 := by rw [posPart_def, negPart_def] @@ -80,6 +90,42 @@ lemma posPart_neg (a : A) : (-a)⁺ = a⁻ := by lemma negPart_neg (a : A) : (-a)⁻ = a⁺ := by rw [← eq_comm, ← sub_eq_zero, ← posPart_neg, neg_neg, sub_self] +section SMul + +variable [StarModule ℝ A] + +@[simp] +lemma posPart_smul {r : ℝ≥0} {a : A} : (r • a)⁺ = r • a⁺ := by + by_cases ha : IsSelfAdjoint a + · simp only [CFC.posPart_def, NNReal.smul_def] + rw [← cfcₙ_comp_smul .., ← cfcₙ_smul ..] + refine cfcₙ_congr fun x hx ↦ ?_ + simp [_root_.posPart_def, mul_max_of_nonneg] + · obtain (rfl | hr) := eq_or_ne r 0 + · simp + · have := (not_iff_not.mpr <| (IsSelfAdjoint.all r).smul_iff hr.isUnit (x := a)) |>.mpr ha + simp [CFC.posPart_def, cfcₙ_apply_of_not_predicate a ha, + cfcₙ_apply_of_not_predicate _ this] + +@[simp] +lemma negPart_smul {r : ℝ≥0} {a : A} : (r • a)⁻ = r • a⁻ := by + simpa using posPart_smul (r := r) (a := -a) + +lemma posPart_smul_of_nonneg {r : ℝ} (hr : 0 ≤ r) {a : A} : (r • a)⁺ = r • a⁺ := + posPart_smul (r := ⟨r, hr⟩) + +lemma posPart_smul_of_nonpos {r : ℝ} (hr : r ≤ 0) {a : A} : (r • a)⁺ = -r • a⁻ := by + nth_rw 1 [← neg_neg r] + rw [neg_smul, ← smul_neg, posPart_smul_of_nonneg (neg_nonneg.mpr hr), posPart_neg] + +lemma negPart_smul_of_nonneg {r : ℝ} (hr : 0 ≤ r) {a : A} : (r • a)⁻ = r • a⁻ := by + conv_lhs => rw [← neg_neg r, neg_smul, negPart_neg, posPart_smul_of_nonpos (by simpa), neg_neg] + +lemma negPart_smul_of_nonpos {r : ℝ} (hr : r ≤ 0) {a : A} : (r • a)⁻ = -r • a⁺ := by + conv_lhs => rw [← neg_neg r, neg_smul, negPart_neg, posPart_smul_of_nonneg (by simpa)] + +end SMul + end Unique variable [PartialOrder A] [StarOrderedRing A] @@ -94,22 +140,46 @@ lemma negPart_nonneg (a : A) : 0 ≤ a⁻ := cfcₙ_nonneg (fun x _ ↦ by positivity) +lemma posPart_eq_of_eq_sub_negPart {a b : A} (hab : a = b - a⁻) (hb : 0 ≤ b := by cfc_tac) : + a⁺ = b := by + have ha := hab.symm ▸ hb.isSelfAdjoint.sub (negPart_nonneg a).isSelfAdjoint + nth_rw 1 [← posPart_sub_negPart a] at hab + simpa using hab + +lemma negPart_eq_of_eq_PosPart_sub {a c : A} (hac : a = a⁺ - c) (hc : 0 ≤ c := by cfc_tac) : + a⁻ = c := by + have ha := hac.symm ▸ (posPart_nonneg a).isSelfAdjoint.sub hc.isSelfAdjoint + nth_rw 1 [← posPart_sub_negPart a] at hac + simpa using hac + +lemma le_posPart {a : A} (ha : IsSelfAdjoint a := by cfc_tac) : a ≤ a⁺ := by + simpa [posPart_sub_negPart a] using sub_le_self a⁺ (negPart_nonneg a) + +lemma neg_negPart_le {a : A} (ha : IsSelfAdjoint a := by cfc_tac) : -a⁻ ≤ a := by + simpa only [posPart_sub_negPart a, ← sub_eq_add_neg] + using le_add_of_nonneg_left (a := -a⁻) (posPart_nonneg a) + variable [NonnegSpectrumClass ℝ A] -lemma eq_posPart_iff (a : A) : a = a⁺ ↔ 0 ≤ a := by +lemma posPart_eq_self (a : A) : a⁺ = a ↔ 0 ≤ a := by refine ⟨fun ha ↦ ha ▸ posPart_nonneg a, fun ha ↦ ?_⟩ - conv_lhs => rw [← cfcₙ_id ℝ a] + conv_rhs => rw [← cfcₙ_id ℝ a] rw [posPart_def] refine cfcₙ_congr (fun x hx ↦ ?_) simpa [_root_.posPart_def] using quasispectrum_nonneg_of_nonneg a ha x hx -lemma negPart_eq_zero_iff (a : A) (ha : IsSelfAdjoint a) : +@[deprecated posPart_eq_self (since := "2024-11-18")] +lemma eq_posPart_iff (a : A) : a = a⁺ ↔ 0 ≤ a := by + rw [eq_comm, posPart_eq_self] + +lemma negPart_eq_zero_iff (a : A) (ha : IsSelfAdjoint a := by cfc_tac) : a⁻ = 0 ↔ 0 ≤ a := by - rw [← eq_posPart_iff] + rw [← posPart_eq_self, eq_comm (b := a)] nth_rw 2 [← posPart_sub_negPart a] simp -lemma eq_negPart_iff (a : A) : a = -a⁻ ↔ a ≤ 0 := by +lemma negPart_eq_neg (a : A) : a⁻ = -a ↔ a ≤ 0 := by + rw [← neg_inj, neg_neg, eq_comm] refine ⟨fun ha ↦ by rw [ha, neg_nonpos]; exact negPart_nonneg a, fun ha ↦ ?_⟩ rw [← neg_nonneg] at ha rw [negPart_def, ← cfcₙ_neg] @@ -121,9 +191,13 @@ lemma eq_negPart_iff (a : A) : a = -a⁻ ↔ a ≤ 0 := by rw [← neg_eq_iff_eq_neg, eq_comm] simpa using quasispectrum_nonneg_of_nonneg _ ha _ hx -lemma posPart_eq_zero_iff (a : A) (ha : IsSelfAdjoint a) : +@[deprecated negPart_eq_neg (since := "2024-11-18")] +lemma eq_negPart_iff (a : A) : a = -a⁻ ↔ a ≤ 0 := by + rw [← neg_inj, neg_neg, eq_comm, negPart_eq_neg] + +lemma posPart_eq_zero_iff (a : A) (ha : IsSelfAdjoint a := by cfc_tac) : a⁺ = 0 ↔ a ≤ 0 := by - rw [← eq_negPart_iff] + rw [← negPart_eq_neg, eq_comm (b := -a)] nth_rw 2 [← posPart_sub_negPart a] simp @@ -140,7 +214,7 @@ open NonUnitalContinuousFunctionalCalculus in precisely `a⁺` and `a⁻`. -/ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) (hb : 0 ≤ b := by cfc_tac) (hc : 0 ≤ c := by cfc_tac) : - b = a⁺ ∧ c = a⁻ := by + a⁺ = b ∧ a⁻ = c := by /- The key idea is to show that `cfcₙ f a = cfcₙ f b + cfcₙ f (-c)` for all real-valued `f` continuous on the union of the spectra of `a`, `b`, and `-c`. Then apply this to `f = (·⁺)`. The equality holds because both sides constitute star homomorphisms which agree on `f = id` since @@ -152,9 +226,8 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) /- It suffices to show `b = a⁺` since `a⁺ - a⁻ = a = b - c` -/ rw [and_iff_left_of_imp ?of_b_eq] case of_b_eq => - rw [← posPart_sub_negPart a] at habc rintro rfl - linear_combination (norm := abel1) habc + exact negPart_eq_of_eq_PosPart_sub habc hc /- `s := σₙ ℝ a ∪ σₙ ℝ b ∪ σₙ ℝ (-c)` is compact and each of these sets are subsets of `s`. Moreover, `0 ∈ s`. -/ let s := σₙ ℝ a ∪ σₙ ℝ b ∪ σₙ ℝ (-c) @@ -163,7 +236,7 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) all_goals exact isCompact_quasispectrum _ obtain ⟨has, hbs, hcs⟩ : σₙ ℝ a ⊆ s ∧ σₙ ℝ b ⊆ s ∧ σₙ ℝ (-c) ⊆ s := by refine ⟨?_, ?_, ?_⟩; all_goals intro; aesop - let _ : Zero s := ⟨0, by aesop⟩ + let zero : Zero s := ⟨0, by aesop⟩ have s0 : (0 : s) = (0 : ℝ) := rfl /- The continuous functional calculi for functions `f g : C(s, ℝ)₀` applied to `b` and `(-c)` are orthogonal (i.e., the product is always zero). -/ @@ -175,8 +248,8 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) all_goals refine g.mul_nonUnitalStarAlgHom_apply_eq_zero s0 _ _ ?_ ?_ (cfcₙHomSuperset_continuous hc' hcs) - all_goals simp only [star_trivial, cfcₙHomSuperset_id' hb' hbs, cfcₙHomSuperset_id' hc' hcs, - mul_neg, hbc, neg_zero] + all_goals simp only [zero, star_trivial, cfcₙHomSuperset_id' hb' hbs, + cfcₙHomSuperset_id' hc' hcs, mul_neg, hbc, neg_zero] have mul₂ (f g : C(s, ℝ)₀) : (cfcₙHomSuperset hc' hcs f) * (cfcₙHomSuperset hb' hbs g) = 0 := by simpa only [star_mul, star_zero, ← map_star, star_trivial] using congr(star $(mul₁ g f)) /- `fun f ↦ cfcₙ f b + cfcₙ f (-c)` defines a star homomorphism `ψ : C(s, ℝ)₀ →⋆ₙₐ[ℝ] A` which @@ -188,13 +261,14 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) toFun := cfcₙHomSuperset hb' hbs + cfcₙHomSuperset hc' hcs map_zero' := by simp [-cfcₙHomSuperset_apply] map_mul' := fun f g ↦ by - simp only [Pi.add_apply, map_mul, mul_add, add_mul, mul₂, add_zero, mul₁, zero_add] + simp only [zero, Pi.add_apply, map_mul, mul_add, add_mul, mul₂, add_zero, mul₁, + zero_add] map_star' := fun f ↦ by simp [← map_star] } have key : (cfcₙHomSuperset ha has) = ψ := UniqueNonUnitalContinuousFunctionalCalculus.eq_of_continuous_of_map_id s rfl (cfcₙHomSuperset ha has) ψ (cfcₙHomSuperset_continuous ha has) ((cfcₙHomSuperset_continuous hb' hbs).add (cfcₙHomSuperset_continuous hc' hcs)) - (by simpa [ψ, -cfcₙHomSuperset_apply, cfcₙHomSuperset_id, sub_eq_add_neg] using habc) + (by simpa [zero, ψ, -cfcₙHomSuperset_apply, cfcₙHomSuperset_id, sub_eq_add_neg] using habc) /- Applying the equality of star homomorphisms to the function `(·⁺ : ℝ → ℝ)` we find that `b = cfcₙ id b + cfcₙ 0 (-c) = cfcₙ (·⁺) b - cfcₙ (·⁺) (-c) = cfcₙ (·⁺) a = a⁺`, where the second equality follows because these functions are equal on the spectra of `b` and `-c`, @@ -203,6 +277,7 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) replace key := congr($key f) simp only [cfcₙHomSuperset_apply, NonUnitalStarAlgHom.coe_mk', NonUnitalAlgHom.coe_mk, ψ, Pi.add_apply, cfcₙHom_eq_cfcₙ_extend (·⁺)] at key + symm calc b = cfcₙ (id : ℝ → ℝ) b + cfcₙ (0 : ℝ → ℝ) (-c) := by simp [cfcₙ_id ℝ b] _ = _ := by @@ -210,8 +285,9 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) all_goals refine cfcₙ_congr fun x hx ↦ Eq.symm ?_ lift x to σₙ ℝ _ using hx - simp only [Subtype.val_injective.extend_apply, comp_apply, coe_mk, ContinuousMap.coe_mk, - Subtype.map_coe, id_eq, posPart_eq_self, f, Pi.zero_apply, posPart_eq_zero] + simp only [zero, Subtype.val_injective.extend_apply, comp_apply, coe_mk, + ContinuousMap.coe_mk, Subtype.map_coe, id_eq, _root_.posPart_eq_self, f, Pi.zero_apply, + posPart_eq_zero] · exact quasispectrum_nonneg_of_nonneg b hb x.val x.property · obtain ⟨x, hx⟩ := x simp only [← neg_nonneg] @@ -223,10 +299,55 @@ lemma posPart_negPart_unique {a b c : A} (habc : a = b - c) (hbc : b * c = 0) _ = a⁺ := by refine cfcₙ_congr fun x hx ↦ ?_ lift x to σₙ ℝ a using hx - simp [Subtype.val_injective.extend_apply, f] + simp [zero, Subtype.val_injective.extend_apply, f] + +end CFC + +end NonUnital + +section Unital + +namespace CFC + +variable {A : Type*} [Ring A] [Algebra ℝ A] [StarRing A] [TopologicalSpace A] +variable [ContinuousFunctionalCalculus ℝ (IsSelfAdjoint : A → Prop)] +variable [UniqueNonUnitalContinuousFunctionalCalculus ℝ A] + +@[simp] +lemma posPart_one : (1 : A)⁺ = 1 := by + rw [CFC.posPart_def, cfcₙ_eq_cfc] + simp + +@[simp] +lemma negPart_one : (1 : A)⁻ = 0 := by + rw [CFC.negPart_def, cfcₙ_eq_cfc] + simp + +@[simp] +lemma posPart_algebraMap (r : ℝ) : (algebraMap ℝ A r)⁺ = algebraMap ℝ A r⁺ := by + rw [CFC.posPart_def, cfcₙ_eq_cfc] + simp + +@[simp] +lemma negPart_algebraMap (r : ℝ) : (algebraMap ℝ A r)⁻ = algebraMap ℝ A r⁻ := by + rw [CFC.negPart_def, cfcₙ_eq_cfc] + simp + +open NNReal in +@[simp] +lemma posPart_algebraMap_nnreal (r : ℝ≥0) : (algebraMap ℝ≥0 A r)⁺ = algebraMap ℝ≥0 A r := by + rw [CFC.posPart_def, cfcₙ_eq_cfc, IsScalarTower.algebraMap_apply ℝ≥0 ℝ A] + simp + +open NNReal in +@[simp] +lemma posPart_natCast (n : ℕ) : (n : A)⁺ = n := by + rw [← map_natCast (algebraMap ℝ≥0 A), posPart_algebraMap_nnreal] end CFC +end Unital + section SpanNonneg variable {A : Type*} [NonUnitalRing A] [Module ℂ A] [SMulCommClass ℂ A A] [IsScalarTower ℂ A A] diff --git a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean index 43d2501f56550..487d14cd2871b 100644 --- a/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean +++ b/Mathlib/Analysis/SpecialFunctions/ContinuousFunctionalCalculus/Rpow.lean @@ -66,7 +66,7 @@ namespace CFC section NonUnital -variable {A : Type*} [PartialOrder A] [NonUnitalNormedRing A] [StarRing A] +variable {A : Type*} [PartialOrder A] [NonUnitalRing A] [TopologicalSpace A] [StarRing A] [Module ℝ≥0 A] [SMulCommClass ℝ≥0 A A] [IsScalarTower ℝ≥0 A A] [NonUnitalContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] @@ -210,8 +210,8 @@ end NonUnital section Unital -variable {A : Type*} [PartialOrder A] [NormedRing A] [StarRing A] - [NormedAlgebra ℝ A] [ContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] +variable {A : Type*} [PartialOrder A] [Ring A] [StarRing A] [TopologicalSpace A] + [Algebra ℝ A] [ContinuousFunctionalCalculus ℝ≥0 (fun (a : A) => 0 ≤ a)] /- ## `rpow` -/ diff --git a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean index 7a9ffe7ff6f72..6a54e8ef68876 100644 --- a/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/ExpDeriv.lean @@ -3,11 +3,10 @@ Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne -/ -import Mathlib.Analysis.Complex.RealDeriv -import Mathlib.Analysis.Calculus.ContDiff.Analytic import Mathlib.Analysis.Calculus.ContDiff.RCLike -import Mathlib.Analysis.Calculus.FDeriv.Analytic import Mathlib.Analysis.Calculus.IteratedDeriv.Lemmas +import Mathlib.Analysis.Complex.RealDeriv +import Mathlib.Analysis.SpecialFunctions.Exp import Mathlib.Analysis.SpecialFunctions.Exponential /-! @@ -20,6 +19,9 @@ In this file we prove that `Complex.exp` and `Real.exp` are infinitely smooth fu exp, derivative -/ +assert_not_exists IsConformalMap +assert_not_exists Conformal + noncomputable section open Filter Asymptotics Set Function diff --git a/Mathlib/Analysis/SpecialFunctions/Integrals.lean b/Mathlib/Analysis/SpecialFunctions/Integrals.lean index ed9d8bc8c55e9..b3b78b374fb6f 100644 --- a/Mathlib/Analysis/SpecialFunctions/Integrals.lean +++ b/Mathlib/Analysis/SpecialFunctions/Integrals.lean @@ -140,10 +140,7 @@ theorem intervalIntegrable_cpow {r : ℂ} (h : 0 ≤ r.re ∨ (0 : ℝ) ∉ [[a, · -- case `c < 0`: integrand is identically constant, *except* at `x = 0` if `r ≠ 0`. apply IntervalIntegrable.symm 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'] - rw [this, integrableOn_union, and_comm]; constructor + rw [← Ioo_union_right hc, integrableOn_union, and_comm]; constructor · refine integrableOn_singleton_iff.mpr (Or.inr ?_) exact isFiniteMeasureOnCompacts_of_isLocallyFiniteMeasure.lt_top_of_isCompact isCompact_singleton @@ -664,7 +661,7 @@ theorem integral_cos_pow_aux : · calc (∫ x in a..b, cos x ^ (n + 2)) = ∫ x in a..b, cos x ^ (n + 1) * cos x := by simp only [_root_.pow_succ] - _ = C + (n + 1) * ∫ x in a..b, sin x ^ 2 * cos x ^ n := by simp [H, h, sq, -neg_add_rev] + _ = C + (n + 1) * ∫ x in a..b, sin x ^ 2 * cos x ^ n := by simp [C, H, h, sq, -neg_add_rev] _ = C + (n + 1) * ∫ x in a..b, cos x ^ n - cos x ^ (n + 2) := by simp [sin_sq, sub_mul, ← pow_add, add_comm] _ = (C + (n + 1) * ∫ x in a..b, cos x ^ n) - (n + 1) * ∫ x in a..b, cos x ^ (n + 2) := by diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean index efd1c239aa8d8..19a01e4add05d 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Basic.lean @@ -383,6 +383,21 @@ theorem isLittleO_const_log_atTop {c : ℝ} : (fun _ => c) =o[atTop] log := by filter_upwards [eventually_gt_atTop 1] with x hx aesop (add safe forward log_pos) +/-- `Real.exp` as a `PartialHomeomorph` with `source = univ` and `target = {z | 0 < z}`. -/ +@[simps] noncomputable def expPartialHomeomorph : PartialHomeomorph ℝ ℝ where + toFun := Real.exp + invFun := Real.log + source := univ + target := Ioi (0 : ℝ) + map_source' x _ := exp_pos x + map_target' _ _ := mem_univ _ + left_inv' _ _ := by simp + right_inv' _ hx := exp_log hx + open_source := isOpen_univ + open_target := isOpen_Ioi + continuousOn_toFun := continuousOn_exp + continuousOn_invFun x hx := (continuousAt_log (ne_of_gt hx)).continuousWithinAt + end Real section Continuity diff --git a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean index b886b2c966010..f1eb252e9bb51 100644 --- a/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Log/Deriv.lean @@ -66,15 +66,27 @@ theorem deriv_log (x : ℝ) : deriv log x = x⁻¹ := theorem deriv_log' : deriv log = Inv.inv := funext deriv_log +theorem contDiffAt_log {n : WithTop ℕ∞} {x : ℝ} : ContDiffAt ℝ n log x ↔ x ≠ 0 := by + refine ⟨fun h ↦ continuousAt_log_iff.1 h.continuousAt, fun hx ↦ ?_⟩ + have A y (hy : 0 < y) : ContDiffAt ℝ n log y := by + apply expPartialHomeomorph.contDiffAt_symm_deriv (f₀' := y) hy.ne' (by simpa) + · convert hasDerivAt_exp (log y) + rw [exp_log hy] + · exact analyticAt_rexp.contDiffAt + rcases hx.lt_or_lt with hx | hx + · have : ContDiffAt ℝ n (log ∘ (fun y ↦ -y)) x := by + apply ContDiffAt.comp + apply A _ (Left.neg_pos_iff.mpr hx) + apply contDiffAt_id.neg + convert this + ext x + simp + · exact A x hx + theorem contDiffOn_log {n : WithTop ℕ∞} : ContDiffOn ℝ n log {0}ᶜ := by - suffices ContDiffOn ℝ ω log {0}ᶜ from this.of_le le_top - rw [← contDiffOn_infty_iff_contDiffOn_omega] - refine (contDiffOn_top_iff_deriv_of_isOpen isOpen_compl_singleton).2 ?_ - simp [differentiableOn_log, contDiffOn_inv] - -theorem contDiffAt_log {n : WithTop ℕ∞} : ContDiffAt ℝ n log x ↔ x ≠ 0 := - ⟨fun h => continuousAt_log_iff.1 h.continuousAt, fun hx => - (contDiffOn_log x hx).contDiffAt <| IsOpen.mem_nhds isOpen_compl_singleton hx⟩ + intro x hx + simp only [mem_compl_iff, mem_singleton_iff] at hx + exact (contDiffAt_log.2 hx).contDiffWithinAt end Real diff --git a/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean b/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean index eb8ceabe6f887..8567fd824e7a8 100644 --- a/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean +++ b/Mathlib/Analysis/SpecialFunctions/NonIntegrable.lean @@ -58,7 +58,7 @@ theorem not_integrableOn_of_tendsto_norm_atTop_of_deriv_isBigO_filter_aux (∀ 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, + have h : ∀ᶠ x : ℝ × ℝ in l ×ˢ l, ∀ 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⟩ diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean index 0c619bd07f671..39bf892635542 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Deriv.lean @@ -368,8 +368,9 @@ theorem contDiff_rpow_const_of_le {p : ℝ} {n : ℕ} (h : ↑n ≤ p) : · exact contDiff_zero.2 (continuous_id.rpow_const fun x => Or.inr <| by simpa using h) · have h1 : 1 ≤ p := le_trans (by simp) h rw [Nat.cast_succ, ← le_sub_iff_add_le] at h - rw [show ((n + 1 : ℕ) : WithTop ℕ∞) = n + 1 from rfl, contDiff_succ_iff_deriv, - deriv_rpow_const' h1] + rw [show ((n + 1 : ℕ) : WithTop ℕ∞) = n + 1 from rfl, + contDiff_succ_iff_deriv, deriv_rpow_const' h1] + simp only [WithTop.natCast_ne_top, analyticOn_univ, IsEmpty.forall_iff, true_and] exact ⟨differentiable_rpow_const h1, contDiff_const.mul (ihn h)⟩ theorem contDiffAt_rpow_const_of_le {x p : ℝ} {n : ℕ} (h : ↑n ≤ p) : @@ -394,7 +395,7 @@ open Real section fderiv variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f g : E → ℝ} {f' g' : E →L[ℝ] ℝ} - {x : E} {s : Set E} {c p : ℝ} {n : ℕ∞} + {x : E} {s : Set E} {c p : ℝ} {n : WithTop ℕ∞} #adaptation_note /-- https://github.com/leanprover/lean4/pull/6024 added `by exact` to deal with unification issues. -/ diff --git a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean index a0af1f9a0076e..0a7f64d0a15aa 100644 --- a/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean +++ b/Mathlib/Analysis/SpecialFunctions/Pow/Real.lean @@ -698,14 +698,50 @@ theorem one_lt_rpow_iff (hx : 0 ≤ x) : 1 < x ^ y ↔ 1 < x ∧ 0 < y ∨ 0 < x · rcases _root_.em (y = 0) with (rfl | hy) <;> simp [*, lt_irrefl, (zero_lt_one' ℝ).not_lt] · simp [one_lt_rpow_iff_of_pos hx, hx] -theorem rpow_le_rpow_of_exponent_ge' (hx0 : 0 ≤ x) (hx1 : x ≤ 1) (hz : 0 ≤ z) (hyz : z ≤ y) : +/-- This is a more general but less convenient version of `rpow_le_rpow_of_exponent_ge`. +This version allows `x = 0`, so it explicitly forbids `x = y = 0`, `z ≠ 0`. -/ +theorem rpow_le_rpow_of_exponent_ge_of_imp (hx0 : 0 ≤ x) (hx1 : x ≤ 1) (hyz : z ≤ y) + (h : x = 0 → y = 0 → z = 0) : x ^ y ≤ x ^ z := by rcases eq_or_lt_of_le hx0 with (rfl | hx0') - · rcases eq_or_lt_of_le hz with (rfl | hz') - · exact (rpow_zero 0).symm ▸ rpow_le_one hx0 hx1 hyz - rw [zero_rpow, zero_rpow] <;> linarith + · rcases eq_or_ne y 0 with rfl | hy0 + · rw [h rfl rfl] + · rw [zero_rpow hy0] + apply zero_rpow_nonneg · exact rpow_le_rpow_of_exponent_ge hx0' hx1 hyz +/-- This version of `rpow_le_rpow_of_exponent_ge` allows `x = 0` but requires `0 ≤ z`. +See also `rpow_le_rpow_of_exponent_ge_of_imp` for the most general version. -/ +theorem rpow_le_rpow_of_exponent_ge' (hx0 : 0 ≤ x) (hx1 : x ≤ 1) (hz : 0 ≤ z) (hyz : z ≤ y) : + x ^ y ≤ x ^ z := + rpow_le_rpow_of_exponent_ge_of_imp hx0 hx1 hyz fun _ hy ↦ le_antisymm (hyz.trans_eq hy) hz + +theorem self_le_rpow_of_le_one (h₁ : 0 ≤ x) (h₂ : x ≤ 1) (h₃ : y ≤ 1) : x ≤ x ^ y := by + simpa only [rpow_one] + using rpow_le_rpow_of_exponent_ge_of_imp h₁ h₂ h₃ fun _ ↦ (absurd · one_ne_zero) + +theorem self_le_rpow_of_one_le (h₁ : 1 ≤ x) (h₂ : 1 ≤ y) : x ≤ x ^ y := by + simpa only [rpow_one] using rpow_le_rpow_of_exponent_le h₁ h₂ + +theorem rpow_le_self_of_le_one (h₁ : 0 ≤ x) (h₂ : x ≤ 1) (h₃ : 1 ≤ y) : x ^ y ≤ x := by + simpa only [rpow_one] + using rpow_le_rpow_of_exponent_ge_of_imp h₁ h₂ h₃ fun _ ↦ (absurd · (one_pos.trans_le h₃).ne') + +theorem rpow_le_self_of_one_le (h₁ : 1 ≤ x) (h₂ : y ≤ 1) : x ^ y ≤ x := by + simpa only [rpow_one] using rpow_le_rpow_of_exponent_le h₁ h₂ + +theorem self_lt_rpow_of_lt_one (h₁ : 0 < x) (h₂ : x < 1) (h₃ : y < 1) : x < x ^ y := by + simpa only [rpow_one] using rpow_lt_rpow_of_exponent_gt h₁ h₂ h₃ + +theorem self_lt_rpow_of_one_lt (h₁ : 1 < x) (h₂ : 1 < y) : x < x ^ y := by + simpa only [rpow_one] using rpow_lt_rpow_of_exponent_lt h₁ h₂ + +theorem rpow_lt_self_of_lt_one (h₁ : 0 < x) (h₂ : x < 1) (h₃ : 1 < y) : x ^ y < x := by + simpa only [rpow_one] using rpow_lt_rpow_of_exponent_gt h₁ h₂ h₃ + +theorem rpow_lt_self_of_one_lt (h₁ : 1 < x) (h₂ : y < 1) : x ^ y < x := by + simpa only [rpow_one] using rpow_lt_rpow_of_exponent_lt h₁ h₂ + theorem rpow_left_injOn {x : ℝ} (hx : x ≠ 0) : InjOn (fun y : ℝ => y ^ x) { y : ℝ | 0 ≤ y } := by rintro y hy z hz (hyz : y ^ x = z ^ x) rw [← rpow_one y, ← rpow_one z, ← mul_inv_cancel₀ hx, rpow_mul hy, rpow_mul hz, hyz] diff --git a/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean b/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean index a9815ec827dfa..c66c0166fed3f 100644 --- a/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean +++ b/Mathlib/Analysis/SpecialFunctions/SmoothTransition.lean @@ -108,7 +108,8 @@ theorem contDiff_polynomial_eval_inv_mul {n : ℕ∞} (p : ℝ[X]) : induction m generalizing p with | zero => exact contDiff_zero.2 <| continuous_polynomial_eval_inv_mul _ | succ m ihm => - refine contDiff_succ_iff_deriv.2 ⟨differentiable_polynomial_eval_inv_mul _, ?_⟩ + rw [show ((m + 1 : ℕ) : WithTop ℕ∞) = m + 1 from rfl] + refine contDiff_succ_iff_deriv.2 ⟨differentiable_polynomial_eval_inv_mul _, by simp, ?_⟩ convert ihm (X ^ 2 * (p - derivative (R := ℝ) p)) using 2 exact (hasDerivAt_polynomial_eval_inv_mul p _).deriv diff --git a/Mathlib/Analysis/SpecialFunctions/Sqrt.lean b/Mathlib/Analysis/SpecialFunctions/Sqrt.lean index 4a26cd60c9cbc..aefa91cf42110 100644 --- a/Mathlib/Analysis/SpecialFunctions/Sqrt.lean +++ b/Mathlib/Analysis/SpecialFunctions/Sqrt.lean @@ -57,7 +57,7 @@ theorem deriv_sqrt_aux {x : ℝ} (hx : x ≠ 0) : theorem hasStrictDerivAt_sqrt {x : ℝ} (hx : x ≠ 0) : HasStrictDerivAt (√·) (1 / (2 * √x)) x := (deriv_sqrt_aux hx).1 -theorem contDiffAt_sqrt {x : ℝ} {n : ℕ∞} (hx : x ≠ 0) : ContDiffAt ℝ n (√·) x := +theorem contDiffAt_sqrt {x : ℝ} {n : WithTop ℕ∞} (hx : x ≠ 0) : ContDiffAt ℝ n (√·) x := (deriv_sqrt_aux hx).2 n theorem hasDerivAt_sqrt {x : ℝ} (hx : x ≠ 0) : HasDerivAt (√·) (1 / (2 * √x)) x := @@ -98,8 +98,8 @@ end deriv section fderiv -variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f : E → ℝ} {n : ℕ∞} {s : Set E} - {x : E} {f' : E →L[ℝ] ℝ} +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {f : E → ℝ} {n : WithTop ℕ∞} + {s : Set E} {x : E} {f' : E →L[ℝ] ℝ} theorem HasFDerivAt.sqrt (hf : HasFDerivAt f f' x) (hx : f x ≠ 0) : HasFDerivAt (fun y => √(f y)) ((1 / (2 * √(f x))) • f') x := diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean index 6919f9dcbb728..7e4c7f3d67170 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Arctan.lean @@ -145,6 +145,13 @@ theorem arctan_zero : arctan 0 = 0 := by simp [arctan_eq_arcsin] @[mono] theorem arctan_strictMono : StrictMono arctan := tanOrderIso.symm.strictMono +@[gcongr] +lemma arctan_lt_arctan {x y : ℝ} (hxy : x < y) : arctan x < arctan y := arctan_strictMono hxy + +@[gcongr] +lemma arctan_le_arctan {x y : ℝ} (hxy : x ≤ y) : arctan x ≤ arctan y := + arctan_strictMono.monotone hxy + theorem arctan_injective : arctan.Injective := arctan_strictMono.injective @[simp] diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean index 43102430e6996..106f49d5a9a1d 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/ArctanDeriv.lean @@ -55,7 +55,7 @@ theorem deriv_tan (x : ℝ) : deriv tan x = 1 / cos x ^ 2 := else (hasDerivAt_tan h).deriv @[simp] -theorem contDiffAt_tan {n x} : ContDiffAt ℝ n tan x ↔ cos x ≠ 0 := +theorem contDiffAt_tan {n : WithTop ℕ∞} {x : ℝ} : ContDiffAt ℝ n tan x ↔ cos x ≠ 0 := ⟨fun h => continuousAt_tan.1 h.continuousAt, fun h => (Complex.contDiffAt_tan.2 <| mod_cast h).real_of_complex⟩ @@ -88,7 +88,7 @@ theorem differentiable_arctan : Differentiable ℝ arctan := theorem deriv_arctan : deriv arctan = fun (x : ℝ) => 1 / (1 + x ^ 2) := funext fun x => (hasDerivAt_arctan x).deriv -theorem contDiff_arctan {n : ℕ∞} : ContDiff ℝ n arctan := +theorem contDiff_arctan {n : WithTop ℕ∞} : ContDiff ℝ n arctan := contDiff_iff_contDiffAt.2 fun x => have : cos (arctan x) ≠ 0 := (cos_arctan_pos x).ne' tanPartialHomeomorph.contDiffAt_symm_deriv (by simpa) trivial (hasDerivAt_tan this) diff --git a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev.lean b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev.lean index 9e2609f0ac9b5..23c49de796496 100644 --- a/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev.lean +++ b/Mathlib/Analysis/SpecialFunctions/Trigonometric/Chebyshev.lean @@ -94,6 +94,18 @@ theorem U_complex_cos (n : ℤ) : (U ℂ n).eval (cos θ) * sin θ = sin ((n + 1 push_cast ring_nf +/-- The `n`-th rescaled Chebyshev polynomial of the first kind (Vieta–Lucas polynomial) evaluates on +`2 * cos θ` to the value `2 * cos (n * θ)`. -/ +@[simp] +theorem C_two_mul_complex_cos (n : ℤ) : (C ℂ n).eval (2 * cos θ) = 2 * cos (n * θ) := by + simp [C_eq_two_mul_T_comp_half_mul_X] + +/-- The `n`-th rescaled Chebyshev polynomial of the second kind (Vieta–Fibonacci polynomial) +evaluates on `2 * cos θ` to the value `sin ((n + 1) * θ) / sin θ`. -/ +@[simp] +theorem S_two_mul_complex_cos (n : ℤ) : (S ℂ n).eval (2 * cos θ) * sin θ = sin ((n + 1) * θ) := by + simp [S_eq_U_comp_half_mul_X] + end Complex /-! ### Real versions -/ @@ -115,6 +127,18 @@ value `sin ((n + 1) * θ) / sin θ`. -/ theorem U_real_cos : (U ℝ n).eval (cos θ) * sin θ = sin ((n + 1) * θ) := mod_cast U_complex_cos θ n +/-- The `n`-th rescaled Chebyshev polynomial of the first kind (Vieta–Lucas polynomial) evaluates on +`2 * cos θ` to the value `2 * cos (n * θ)`. -/ +@[simp] +theorem C_two_mul_real_cos : (C ℝ n).eval (2 * cos θ) = 2 * cos (n * θ) := by + simp [C_eq_two_mul_T_comp_half_mul_X] + +/-- The `n`-th rescaled Chebyshev polynomial of the second kind (Vieta–Fibonacci polynomial) +evaluates on `2 * cos θ` to the value `sin ((n + 1) * θ) / sin θ`. -/ +@[simp] +theorem S_two_mul_real_cos : (S ℝ n).eval (2 * cos θ) * sin θ = sin ((n + 1) * θ) := by + simp [S_eq_U_comp_half_mul_X] + end Real end Polynomial.Chebyshev diff --git a/Mathlib/Analysis/SpecificLimits/Basic.lean b/Mathlib/Analysis/SpecificLimits/Basic.lean index e9bbbad7a0c52..d86c021d2cfec 100644 --- a/Mathlib/Analysis/SpecificLimits/Basic.lean +++ b/Mathlib/Analysis/SpecificLimits/Basic.lean @@ -273,8 +273,14 @@ protected theorem ENNReal.tendsto_pow_atTop_nhds_top_iff {r : ℝ≥0∞} : simp only [ENNReal.tendsto_pow_atTop_nhds_zero_iff, inv_zero] at obs simpa [← ENNReal.inv_pow] using obs <| ENNReal.inv_lt_one.mpr r_gt_one -/-! ### Geometric series -/ +lemma ENNReal.eq_zero_of_le_mul_pow {x r : ℝ≥0∞} {ε : ℝ≥0} (hr : r < 1) + (h : ∀ n : ℕ, x ≤ ε * r ^ n) : x = 0 := by + rw [← nonpos_iff_eq_zero] + refine ge_of_tendsto' (f := fun (n : ℕ) ↦ ε * r ^ n) (x := atTop) ?_ h + rw [← mul_zero (M₀ := ℝ≥0∞) (a := ε)] + exact Tendsto.const_mul (tendsto_pow_atTop_nhds_zero_of_lt_one hr) (Or.inr coe_ne_top) +/-! ### Geometric series -/ section Geometric diff --git a/Mathlib/Analysis/SumOverResidueClass.lean b/Mathlib/Analysis/SumOverResidueClass.lean index d0109a33064e6..eb5a5d4f11043 100644 --- a/Mathlib/Analysis/SumOverResidueClass.lean +++ b/Mathlib/Analysis/SumOverResidueClass.lean @@ -64,7 +64,7 @@ lemma not_summable_indicator_mod_of_antitone_of_neg {m : ℕ} [hm : NeZero m] {f rw [← ZMod.natCast_zmod_val k, summable_indicator_mod_iff_summable] exact not_summable_of_antitone_of_neg (hf.comp_monotone <| (Covariant.monotone_of_const m).add_const k.val) <| - (hf <| (Nat.le_mul_of_pos_left n Fin.size_pos').trans <| Nat.le_add_right ..).trans_lt hn + (hf <| (Nat.le_mul_of_pos_left n Fin.pos').trans <| Nat.le_add_right ..).trans_lt hn /-- If a decreasing sequence of real numbers is summable on one residue class modulo `m`, then it is also summable on every other residue class mod `m`. -/ diff --git a/Mathlib/CategoryTheory/Abelian/EpiWithInjectiveKernel.lean b/Mathlib/CategoryTheory/Abelian/EpiWithInjectiveKernel.lean index 40e7feb1d78af..5c34bd58bd141 100644 --- a/Mathlib/CategoryTheory/Abelian/EpiWithInjectiveKernel.lean +++ b/Mathlib/CategoryTheory/Abelian/EpiWithInjectiveKernel.lean @@ -43,7 +43,7 @@ lemma epiWithInjectiveKernel_iff {X Y : C} (g : X ⟶ Y) : exact ⟨_, inferInstance, _, S.zero, ⟨ShortComplex.Splitting.ofExactOfRetraction S (S.exact_of_f_is_kernel (kernelIsKernel g)) (Injective.factorThru (𝟙 _) (kernel.ι g)) - (by simp) inferInstance⟩⟩ + (by simp [S]) inferInstance⟩⟩ · rintro ⟨I, _, f, w, ⟨σ⟩⟩ have : IsSplitEpi g := ⟨σ.s, σ.s_g⟩ let e : I ≅ kernel g := diff --git a/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean index e11ac111c917c..9e81a28ffd8e2 100644 --- a/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean +++ b/Mathlib/CategoryTheory/Abelian/GrothendieckAxioms.lean @@ -3,11 +3,12 @@ Copyright (c) 2023 Adam Topaz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Isaac Hernando, Coleton Kotch, Adam Topaz -/ - +import Mathlib.Algebra.Homology.ShortComplex.ExactFunctor +import Mathlib.CategoryTheory.Abelian.FunctorCategory import Mathlib.CategoryTheory.Limits.Constructions.Filtered -import Mathlib.CategoryTheory.Limits.Shapes.Biproducts import Mathlib.CategoryTheory.Limits.Preserves.FunctorCategory - +import Mathlib.CategoryTheory.Limits.Shapes.Countable +import Mathlib.Logic.Equiv.List /-! # Grothendieck Axioms @@ -17,9 +18,10 @@ basic facts about them. ## Definitions -- `AB4` -- a category satisfies `AB4` provided that coproducts are exact. -- `AB5` -- a category satisfies `AB5` provided that filtered colimits are exact. -- The duals of the above definitions, called `AB4Star` and `AB5Star`. +- `HasExactColimitsOfShape J` -- colimits of shape `J` are exact. +- The dual of the above definitions, called `HasExactLimitsOfShape`. +- `AB4` -- coproducts are exact (this is formulated in terms of `HasExactColimitsOfShape`). +- `AB5` -- filtered colimits are exact (this is formulated in terms of `HasExactColimitsOfShape`). ## Theorems @@ -50,63 +52,226 @@ namespace CategoryTheory open Limits -universe v v' u u' w +attribute [instance] comp_preservesFiniteLimits comp_preservesFiniteColimits + +universe w w' w₂ w₂' v v' u u' variable (C : Type u) [Category.{v} C] -attribute [local instance] hasCoproducts_of_finite_and_filtered +/-- +A category `C` is said to have exact colimits of shape `J` provided that colimits of shape `J` +exist and are exact (in the sense that they preserve finite limits). +-/ +class HasExactColimitsOfShape (J : Type u') [Category.{v'} J] (C : Type u) [Category.{v} C] + [HasColimitsOfShape J C] where + /-- Exactness of `J`-shaped colimits stated as `colim : (J ⥤ C) ⥤ C` preserving finite limits. -/ + preservesFiniteLimits : PreservesFiniteLimits (colim (J := J) (C := C)) + +/-- +A category `C` is said to have exact limits of shape `J` provided that limits of shape `J` +exist and are exact (in the sense that they preserve finite colimits). +-/ +class HasExactLimitsOfShape (J : Type u') [Category.{v'} J] (C : Type u) [Category.{v} C] + [HasLimitsOfShape J C] where + /-- Exactness of `J`-shaped limits stated as `lim : (J ⥤ C) ⥤ C` preserving finite colimits. -/ + preservesFiniteColimits : PreservesFiniteColimits (lim (J := J) (C := C)) + +attribute [instance] HasExactColimitsOfShape.preservesFiniteLimits + HasExactLimitsOfShape.preservesFiniteColimits + +/-- +Transport a `HasExactColimitsOfShape` along an equivalence of the shape. + +Note: When `C` has finite limits, this lemma holds with the equivalence replaced by a final +functor, see `hasExactColimitsOfShape_of_final` below. +-/ +lemma hasExactColimitsOfShape_of_equiv {J J' : Type*} [Category J] [Category J'] (e : J ≌ J') + [HasColimitsOfShape J C] [HasExactColimitsOfShape J C] : + haveI : HasColimitsOfShape J' C := hasColimitsOfShape_of_equivalence e + HasExactColimitsOfShape J' C := + haveI : HasColimitsOfShape J' C := hasColimitsOfShape_of_equivalence e + ⟨preservesFiniteLimits_of_natIso (Functor.Final.colimIso e.functor)⟩ + +/-- +Transport a `HasExactLimitsOfShape` along an equivalence of the shape. + +Note: When `C` has finite colimits, this lemma holds with the equivalence replaced by a initial +functor, see `hasExactLimitsOfShape_of_initial` below. +-/ +lemma hasExactLimitsOfShape_of_equiv {J J' : Type*} [Category J] [Category J'] (e : J ≌ J') + [HasLimitsOfShape J C] [HasExactLimitsOfShape J C] : + haveI : HasLimitsOfShape J' C := hasLimitsOfShape_of_equivalence e + HasExactLimitsOfShape J' C := + haveI : HasLimitsOfShape J' C := hasLimitsOfShape_of_equivalence e + ⟨preservesFiniteColimits_of_natIso (Functor.Initial.limIso e.functor)⟩ + +/-- +A category `C` which has coproducts is said to have `AB4` of size `w` provided that +coproducts of size `w` are exact. +-/ +@[pp_with_univ] +class AB4OfSize [HasCoproducts.{w} C] where + ofShape (α : Type w) : HasExactColimitsOfShape (Discrete α) C + +attribute [instance] AB4OfSize.ofShape /-- A category `C` which has coproducts is said to have `AB4` provided that coproducts are exact. -/ -class AB4 [HasCoproducts C] where - /-- Exactness of coproducts stated as `colim : (Discrete α ⥤ C) ⥤ C` preserving limits. -/ - preservesFiniteLimits (α : Type v) : - PreservesFiniteLimits (colim (J := Discrete α) (C := C)) +abbrev AB4 [HasCoproducts C] := AB4OfSize.{v} C + +lemma AB4OfSize_shrink [HasCoproducts.{max w w'} C] [AB4OfSize.{max w w'} C] : + haveI : HasCoproducts.{w} C := hasCoproducts_shrink.{w, w'} + AB4OfSize.{w} C := + haveI := hasCoproducts_shrink.{w, w'} (C := C) + ⟨fun J ↦ hasExactColimitsOfShape_of_equiv C + (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w'} J) ≌ _)⟩ + +instance (priority := 100) [HasCoproducts.{w} C] [AB4OfSize.{w} C] : + haveI : HasCoproducts.{0} C := hasCoproducts_shrink + AB4OfSize.{0} C := AB4OfSize_shrink C + +/-- A category `C` which has products is said to have `AB4Star` (in literature `AB4*`) +provided that products are exact. -/ +@[pp_with_univ] +class AB4StarOfSize [HasProducts.{w} C] where + ofShape (α : Type w) : HasExactLimitsOfShape (Discrete α) C -attribute [instance] AB4.preservesFiniteLimits +attribute [instance] AB4StarOfSize.ofShape /-- A category `C` which has products is said to have `AB4Star` (in literature `AB4*`) provided that products are exact. -/ -class AB4Star [HasProducts C] where - /-- Exactness of products stated as `lim : (Discrete α ⥤ C) ⥤ C` preserving colimits. -/ - preservesFiniteColimits (α : Type v) : - PreservesFiniteColimits (lim (J := Discrete α) (C := C)) +abbrev AB4Star [HasProducts C] := AB4StarOfSize.{v} C + +lemma AB4StarOfSize_shrink [HasProducts.{max w w'} C] [AB4StarOfSize.{max w w'} C] : + haveI : HasProducts.{w} C := hasProducts_shrink.{w, w'} + AB4StarOfSize.{w} C := + haveI := hasProducts_shrink.{w, w'} (C := C) + ⟨fun J ↦ hasExactLimitsOfShape_of_equiv C + (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w'} J) ≌ _)⟩ + +instance (priority := 100) [HasProducts.{w} C] [AB4StarOfSize.{w} C] : + haveI : HasProducts.{0} C := hasProducts_shrink + AB4StarOfSize.{0} C := AB4StarOfSize_shrink C + +/-- +A category `C` which has countable coproducts is said to have countable `AB4` provided that +countable coproducts are exact. +-/ +class CountableAB4 [HasCountableCoproducts C] where + ofShape (α : Type) [Countable α] : HasExactColimitsOfShape (Discrete α) C + +instance (priority := 100) [HasCoproducts.{0} C] [AB4OfSize.{0} C] : CountableAB4 C := + ⟨inferInstance⟩ + +/-- +A category `C` which has countable coproducts is said to have countable `AB4Star` provided that +countable products are exact. +-/ +class CountableAB4Star [HasCountableProducts C] where + ofShape (α : Type) [Countable α] : HasExactLimitsOfShape (Discrete α) C + +instance (priority := 100) [HasProducts.{0} C] [AB4StarOfSize.{0} C] : CountableAB4Star C := + ⟨inferInstance⟩ -attribute [instance] AB4Star.preservesFiniteColimits +attribute [instance] CountableAB4.ofShape CountableAB4Star.ofShape + +/-- +A category `C` which has filtered colimits of a given size is said to have `AB5` of that size +provided that these filtered colimits are exact. + +`AB5OfSize.{w, w'} C` means that `C` has exact colimits of shape `J : Type w'` with +`Category.{w} J` such that `J` is filtered. +-/ +@[pp_with_univ] +class AB5OfSize [HasFilteredColimitsOfSize.{w, w'} C] where + ofShape (J : Type w') [Category.{w} J] [IsFiltered J] : HasExactColimitsOfShape J C + +attribute [instance] AB5OfSize.ofShape /-- A category `C` which has filtered colimits is said to have `AB5` provided that filtered colimits are exact. -/ -class AB5 [HasFilteredColimits C] where - /-- Exactness of filtered colimits stated as `colim : (J ⥤ C) ⥤ C` on filtered `J` - preserving limits. -/ - preservesFiniteLimits (J : Type v) [SmallCategory J] [IsFiltered J] : - PreservesFiniteLimits (colim (J := J) (C := C)) - -attribute [instance] AB5.preservesFiniteLimits +abbrev AB5 [HasFilteredColimits C] := AB5OfSize.{v, v} C + +lemma AB5OfSize_of_univLE [HasFilteredColimitsOfSize.{w₂, w₂'} C] [UnivLE.{w, w₂}] + [UnivLE.{w', w₂'}] [AB5OfSize.{w₂, w₂'} C] : + haveI : HasFilteredColimitsOfSize.{w, w'} C := hasFilteredColimitsOfSize_of_univLE.{w} + AB5OfSize.{w, w'} C := by + haveI : HasFilteredColimitsOfSize.{w, w'} C := hasFilteredColimitsOfSize_of_univLE.{w} + constructor + intro J _ _ + haveI := IsFiltered.of_equivalence ((ShrinkHoms.equivalence.{w₂} J).trans <| + Shrink.equivalence.{w₂'} (ShrinkHoms.{w'} J)) + exact hasExactColimitsOfShape_of_equiv _ ((ShrinkHoms.equivalence.{w₂} J).trans <| + Shrink.equivalence.{w₂'} (ShrinkHoms.{w'} J)).symm + +lemma AB5OfSize_shrink [HasFilteredColimitsOfSize.{max w w₂, max w' w₂'} C] + [AB5OfSize.{max w w₂, max w' w₂'} C] : + haveI : HasFilteredColimitsOfSize.{w, w'} C := hasFilteredColimitsOfSize_shrink + AB5OfSize.{w, w'} C := + AB5OfSize_of_univLE C /-- A category `C` which has cofiltered limits is said to have `AB5Star` (in literature `AB5*`) provided that cofiltered limits are exact. -/ -class AB5Star [HasCofilteredLimits C] where - /-- Exactness of cofiltered limits stated as `lim : (J ⥤ C) ⥤ C` on cofiltered `J` - preserving colimits. -/ - preservesFiniteColimits (J : Type v) [SmallCategory J] [IsCofiltered J] : - PreservesFiniteColimits (lim (J := J) (C := C)) +@[pp_with_univ] +class AB5StarOfSize [HasCofilteredLimitsOfSize.{w, w'} C] where + ofShape (J : Type w') [Category.{w} J] [IsCofiltered J] : HasExactLimitsOfShape J C -attribute [instance] AB5Star.preservesFiniteColimits +attribute [instance] AB5StarOfSize.ofShape -noncomputable section +/-- +A category `C` which has cofiltered limits is said to have `AB5Star` (in literature `AB5*`) +provided that cofiltered limits are exact. +-/ +abbrev AB5Star [HasCofilteredLimits C] := AB5StarOfSize.{v, v} C + +lemma AB5StarOfSize_of_univLE [HasCofilteredLimitsOfSize.{w₂, w₂'} C] [UnivLE.{w, w₂}] + [UnivLE.{w', w₂'}] [AB5StarOfSize.{w₂, w₂'} C] : + haveI : HasCofilteredLimitsOfSize.{w, w'} C := hasCofilteredLimitsOfSize_of_univLE.{w} + AB5StarOfSize.{w, w'} C := by + haveI : HasCofilteredLimitsOfSize.{w, w'} C := hasCofilteredLimitsOfSize_of_univLE.{w} + constructor + intro J _ _ + haveI := IsCofiltered.of_equivalence ((ShrinkHoms.equivalence.{w₂} J).trans <| + Shrink.equivalence.{w₂'} (ShrinkHoms.{w'} J)) + exact hasExactLimitsOfShape_of_equiv _ ((ShrinkHoms.equivalence.{w₂} J).trans <| + Shrink.equivalence.{w₂'} (ShrinkHoms.{w'} J)).symm + +lemma AB5StarOfSize_shrink [HasCofilteredLimitsOfSize.{max w w₂, max w' w₂'} C] + [AB5StarOfSize.{max w w₂, max w' w₂'} C] : + haveI : HasCofilteredLimitsOfSize.{w, w'} C := hasCofilteredLimitsOfSize_shrink + AB5StarOfSize.{w, w'} C := + AB5StarOfSize_of_univLE C + +/-- `HasExactColimitsOfShape` can be "pushed forward" along final functors -/ +lemma hasExactColimitsOfShape_of_final [HasFiniteLimits C] {J J' : Type*} [Category J] [Category J'] + (F : J ⥤ J') [F.Final] [HasColimitsOfShape J' C] [HasColimitsOfShape J C] + [HasExactColimitsOfShape J C] : HasExactColimitsOfShape J' C where + preservesFiniteLimits := + letI : PreservesFiniteLimits ((whiskeringLeft J J' C).obj F) := ⟨fun _ ↦ inferInstance⟩ + letI := comp_preservesFiniteLimits ((whiskeringLeft J J' C).obj F) colim + preservesFiniteLimits_of_natIso (Functor.Final.colimIso F) + +/-- `HasExactLimitsOfShape` can be "pushed forward" along initial functors -/ +lemma hasExactLimitsOfShape_of_initial [HasFiniteColimits C] {J J' : Type*} [Category J] + [Category J'] (F : J ⥤ J') [F.Initial] [HasLimitsOfShape J' C] [HasLimitsOfShape J C] + [HasExactLimitsOfShape J C] : HasExactLimitsOfShape J' C where + preservesFiniteColimits := + letI : PreservesFiniteColimits ((whiskeringLeft J J' C).obj F) := ⟨fun _ ↦ inferInstance⟩ + letI := comp_preservesFiniteColimits ((whiskeringLeft J J' C).obj F) lim + preservesFiniteColimits_of_natIso (Functor.Initial.limIso F) + +section AB4OfAB5 + +variable {α : Type w} [HasZeroMorphisms C] [HasFiniteBiproducts C] [HasFiniteLimits C] open CoproductsFromFiniteFiltered -variable {α : Type w} -variable [HasZeroMorphisms C] [HasFiniteBiproducts C] [HasFiniteLimits C] - instance preservesFiniteLimits_liftToFinset : PreservesFiniteLimits (liftToFinset C α) := preservesFiniteLimits_of_evaluation _ fun I => letI : PreservesFiniteLimits (colim (J := Discrete I) (C := C)) := @@ -117,15 +282,192 @@ instance preservesFiniteLimits_liftToFinset : PreservesFiniteLimits (liftToFinse letI : PreservesFiniteLimits ((whiskeringLeft (Discrete I) (Discrete α) C).obj (Discrete.functor (·.val)) ⋙ colim) := comp_preservesFiniteLimits _ _ - preservesFiniteLimits_of_natIso (liftToFinsetEvaluationIso I).symm + preservesFiniteLimits_of_natIso (liftToFinsetEvaluationIso I).symm -/-- A category with finite biproducts and finite limits is AB4 if it is AB5. -/ -lemma AB4.of_AB5 [HasFilteredColimits C] [AB5 C] : AB4 C where - preservesFiniteLimits J := +variable (J : Type*) + +/-- +`HasExactColimitsOfShape (Finset (Discrete J)) C` implies `HasExactColimitsOfShape (Discrete J) C` +-/ +lemma hasExactColimitsOfShape_discrete_of_hasExactColimitsOfShape_finset_discrete + [HasColimitsOfShape (Discrete J) C] [HasColimitsOfShape (Finset (Discrete J)) C] + [HasExactColimitsOfShape (Finset (Discrete J)) C] : HasExactColimitsOfShape (Discrete J) C where + preservesFiniteLimits := letI : PreservesFiniteLimits (liftToFinset C J ⋙ colim) := comp_preservesFiniteLimits _ _ preservesFiniteLimits_of_natIso (liftToFinsetColimIso) +attribute [local instance] hasCoproducts_of_finite_and_filtered in +/-- A category with finite biproducts and finite limits is AB4 if it is AB5. -/ +lemma AB4.of_AB5 [HasFilteredColimitsOfSize.{w, w} C] + [AB5OfSize.{w, w} C] : AB4OfSize.{w} C where + ofShape _ := hasExactColimitsOfShape_discrete_of_hasExactColimitsOfShape_finset_discrete _ _ + +/-- +A category with finite biproducts and finite limits has countable AB4 if sequential colimits are +exact. +-/ +lemma CountableAB4.of_countableAB5 [HasColimitsOfShape ℕ C] [HasExactColimitsOfShape ℕ C] + [HasCountableCoproducts C] : CountableAB4 C where + ofShape J := + have : HasColimitsOfShape (Finset (Discrete J)) C := + Functor.Final.hasColimitsOfShape_of_final + (IsFiltered.sequentialFunctor (Finset (Discrete J))) + have := hasExactColimitsOfShape_of_final C (IsFiltered.sequentialFunctor (Finset (Discrete J))) + hasExactColimitsOfShape_discrete_of_hasExactColimitsOfShape_finset_discrete _ _ + +end AB4OfAB5 + +section AB4StarOfAB5Star + +variable {α : Type w} [HasZeroMorphisms C] [HasFiniteBiproducts C] [HasFiniteColimits C] + +open ProductsFromFiniteCofiltered + +instance preservesFiniteColimits_liftToFinset : PreservesFiniteColimits (liftToFinset C α) := + preservesFiniteColimits_of_evaluation _ fun ⟨I⟩ => + letI : PreservesFiniteColimits (lim (J := Discrete I) (C := C)) := + preservesFiniteColimits_of_natIso HasBiproductsOfShape.colimIsoLim + letI : PreservesFiniteColimits ((whiskeringLeft (Discrete I) (Discrete α) C).obj + (Discrete.functor fun x ↦ ↑x)) := ⟨fun _ _ _ => inferInstance⟩ + letI : PreservesFiniteColimits ((whiskeringLeft (Discrete I) (Discrete α) C).obj + (Discrete.functor (·.val)) ⋙ lim) := + comp_preservesFiniteColimits _ _ + preservesFiniteColimits_of_natIso (liftToFinsetEvaluationIso _ _ I).symm + +variable (J : Type*) + +/-- +`HasExactLimitsOfShape (Finset (Discrete J))ᵒᵖ C` implies `HasExactLimitsOfShape (Discrete J) C` +-/ +lemma hasExactLimitsOfShape_discrete_of_hasExactLimitsOfShape_finset_discrete_op + [HasLimitsOfShape (Discrete J) C] [HasLimitsOfShape (Finset (Discrete J))ᵒᵖ C] + [HasExactLimitsOfShape (Finset (Discrete J))ᵒᵖ C] : + HasExactLimitsOfShape (Discrete J) C where + preservesFiniteColimits := + letI : PreservesFiniteColimits (ProductsFromFiniteCofiltered.liftToFinset C J ⋙ lim) := + comp_preservesFiniteColimits _ _ + preservesFiniteColimits_of_natIso (ProductsFromFiniteCofiltered.liftToFinsetLimIso _ _) + +attribute [local instance] hasProducts_of_finite_and_cofiltered in +/-- A category with finite biproducts and finite limits is AB4 if it is AB5. -/ +lemma AB4Star.of_AB5Star [HasCofilteredLimitsOfSize.{w, w} C] [AB5StarOfSize.{w, w} C] : + AB4StarOfSize.{w} C where + ofShape _ := hasExactLimitsOfShape_discrete_of_hasExactLimitsOfShape_finset_discrete_op _ _ + +/-- +A category with finite biproducts and finite limits has countable AB4* if sequential limits are +exact. +-/ +lemma CountableAB4Star.of_countableAB5Star [HasLimitsOfShape ℕᵒᵖ C] [HasExactLimitsOfShape ℕᵒᵖ C] + [HasCountableProducts C] : CountableAB4Star C where + ofShape J := + have : HasLimitsOfShape (Finset (Discrete J))ᵒᵖ C := + Functor.Initial.hasLimitsOfShape_of_initial + (IsFiltered.sequentialFunctor (Finset (Discrete J))).op + have := hasExactLimitsOfShape_of_initial C + (IsFiltered.sequentialFunctor (Finset (Discrete J))).op + hasExactLimitsOfShape_discrete_of_hasExactLimitsOfShape_finset_discrete_op _ _ + +end AB4StarOfAB5Star + +/-- +Checking exactness of colimits of shape `Discrete ℕ` and `Discrete J` for finite `J` is enough for +countable AB4. +-/ +lemma CountableAB4.of_hasExactColimitsOfShape_nat_and_finite [HasCountableCoproducts C] + [HasFiniteLimits C] [∀ (J : Type) [Finite J], HasExactColimitsOfShape (Discrete J) C] + [HasExactColimitsOfShape (Discrete ℕ) C] : + CountableAB4 C where + ofShape J := by + by_cases h : Finite J + · infer_instance + · have : Infinite J := ⟨h⟩ + let _ := Encodable.ofCountable J + let _ := Denumerable.ofEncodableOfInfinite J + exact hasExactColimitsOfShape_of_final C (Discrete.equivalence (Denumerable.eqv J)).inverse + +/-- +Checking exactness of limits of shape `Discrete ℕ` and `Discrete J` for finite `J` is enough for +countable AB4*. +-/ +lemma CountableAB4Star.of_hasExactLimitsOfShape_nat_and_finite [HasCountableProducts C] + [HasFiniteColimits C] [∀ (J : Type) [Finite J], HasExactLimitsOfShape (Discrete J) C] + [HasExactLimitsOfShape (Discrete ℕ) C] : + CountableAB4Star C where + ofShape J := by + by_cases h : Finite J + · infer_instance + · have : Infinite J := ⟨h⟩ + let _ := Encodable.ofCountable J + let _ := Denumerable.ofEncodableOfInfinite J + exact hasExactLimitsOfShape_of_initial C (Discrete.equivalence (Denumerable.eqv J)).inverse + +section EpiMono + +open Functor + +section + +variable [HasZeroMorphisms C] [HasFiniteBiproducts C] + +noncomputable instance hasExactColimitsOfShape_discrete_finite (J : Type*) [Finite J] : + HasExactColimitsOfShape (Discrete J) C where + preservesFiniteLimits := preservesFiniteLimits_of_natIso HasBiproductsOfShape.colimIsoLim.symm + +noncomputable instance hasExactLimitsOfShape_discrete_finite {J : Type*} [Finite J] : + HasExactLimitsOfShape (Discrete J) C where + preservesFiniteColimits := preservesFiniteColimits_of_natIso HasBiproductsOfShape.colimIsoLim + +/-- +Checking AB of shape `Discrete ℕ` is enough for countable AB4, provided that the category has +finite biproducts and finite limits. +-/ +lemma CountableAB4.of_hasExactColimitsOfShape_nat [HasFiniteLimits C] [HasCountableCoproducts C] + [HasExactColimitsOfShape (Discrete ℕ) C] : CountableAB4 C := by + apply (config := { allowSynthFailures := true }) + CountableAB4.of_hasExactColimitsOfShape_nat_and_finite + exact fun _ ↦ inferInstance + +/-- +Checking AB* of shape `Discrete ℕ` is enough for countable AB4*, provided that the category has +finite biproducts and finite colimits. +-/ +lemma CountableAB4Star.of_hasExactLimitsOfShape_nat [HasFiniteColimits C] + [HasCountableProducts C] [HasExactLimitsOfShape (Discrete ℕ) C] : CountableAB4Star C := by + apply (config := { allowSynthFailures := true }) + CountableAB4Star.of_hasExactLimitsOfShape_nat_and_finite + exact fun _ ↦ inferInstance + end +variable [Abelian C] (J : Type u') [Category.{v'} J] + +attribute [local instance] preservesBinaryBiproducts_of_preservesBinaryCoproducts + preservesBinaryBiproducts_of_preservesBinaryProducts + +/-- +If `colim` of shape `J` into an abelian category `C` preserves monomorphisms, then `C` has AB of +shape `J`. +-/ +lemma hasExactColimitsOfShape_of_preservesMono [HasColimitsOfShape J C] + [PreservesMonomorphisms (colim (J := J) (C := C))] : HasExactColimitsOfShape J C where + preservesFiniteLimits := by + apply (config := { allowSynthFailures := true }) preservesFiniteLimits_of_preservesHomology + · exact preservesHomology_of_preservesMonos_and_cokernels _ + · exact additive_of_preservesBinaryBiproducts _ + +/-- +If `lim` of shape `J` into an abelian category `C` preserves epimorphisms, then `C` has AB* of +shape `J`. +-/ +lemma hasExactLimitsOfShape_of_preservesEpi [HasLimitsOfShape J C] + [PreservesEpimorphisms (lim (J := J) (C := C))] : HasExactLimitsOfShape J C where + preservesFiniteColimits := by + apply (config := { allowSynthFailures := true }) preservesFiniteColimits_of_preservesHomology + · exact preservesHomology_of_preservesEpis_and_kernels _ + · exact additive_of_preservesBinaryBiproducts _ + +end EpiMono + end CategoryTheory diff --git a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean index 447bcadee24a4..8aa0fd2f01e4b 100644 --- a/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean +++ b/Mathlib/CategoryTheory/Abelian/Pseudoelements.lean @@ -427,20 +427,20 @@ section Module /-- In the category `Module R`, if `x` and `y` are pseudoequal, then the range of the associated morphisms is the same. -/ theorem ModuleCat.eq_range_of_pseudoequal {R : Type*} [CommRing R] {G : ModuleCat R} {x y : Over G} - (h : PseudoEqual G x y) : LinearMap.range x.hom = LinearMap.range y.hom := by + (h : PseudoEqual G x y) : LinearMap.range x.hom.hom = LinearMap.range y.hom.hom := by obtain ⟨P, p, q, hp, hq, H⟩ := h refine Submodule.ext fun a => ⟨fun ha => ?_, fun ha => ?_⟩ · obtain ⟨a', ha'⟩ := ha obtain ⟨a'', ha''⟩ := (ModuleCat.epi_iff_surjective p).1 hp a' refine ⟨q a'', ?_⟩ - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [← LinearMap.comp_apply, ← ModuleCat.comp_def, ← H, - ModuleCat.comp_def, LinearMap.comp_apply, ha'', ha'] + dsimp at ha' ⊢ + rw [← LinearMap.comp_apply, ← ModuleCat.hom_comp, ← H, + ModuleCat.hom_comp, LinearMap.comp_apply, ha'', ha'] · obtain ⟨a', ha'⟩ := ha obtain ⟨a'', ha''⟩ := (ModuleCat.epi_iff_surjective q).1 hq a' refine ⟨p a'', ?_⟩ - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [← LinearMap.comp_apply, ← ModuleCat.comp_def, H, ModuleCat.comp_def, LinearMap.comp_apply, + dsimp at ha' ⊢ + rw [← LinearMap.comp_apply, ← ModuleCat.hom_comp, H, ModuleCat.hom_comp, LinearMap.comp_apply, ha'', ha'] end Module diff --git a/Mathlib/CategoryTheory/Abelian/Refinements.lean b/Mathlib/CategoryTheory/Abelian/Refinements.lean index 8dffabb705f3f..75582a7bcc024 100644 --- a/Mathlib/CategoryTheory/Abelian/Refinements.lean +++ b/Mathlib/CategoryTheory/Abelian/Refinements.lean @@ -44,17 +44,17 @@ category is exact if and only if it is exact up to refinements (see `ShortComplex.exact_iff_exact_up_to_refinements`). As it is outlined in the documentation of the file -`CategoryTheory.Abelian.Pseudoelements`, the Freyd-Mitchell +`Mathlib.CategoryTheory.Abelian.Pseudoelements`, the Freyd-Mitchell embedding theorem implies the existence of a faithful and exact functor `ι` from an abelian category `C` to the category of abelian groups. If we define a pseudo-element of `X : C` to be an element in `ι.obj X`, one may do diagram chases in any abelian category using these pseudo-elements. However, using this approach would require proving this embedding theorem! Currently, mathlib contains a weaker notion of pseudo-elements -`CategoryTheory.Abelian.Pseudoelements`. Some theorems can be obtained +`Mathlib.CategoryTheory.Abelian.Pseudoelements`. Some theorems can be obtained using this notion, but there is the issue that for this notion of pseudo-elements a morphism `X ⟶ Y` in `C` is not determined by -its action on pseudo-elements (see also `Counterexamples/Pseudoelement`). +its action on pseudo-elements (see also `Counterexamples/Pseudoelement.lean`). On the contrary, the approach consisting of working up to refinements does not require the introduction of other types: we only need to work with morphisms `A ⟶ X` in `C` which we may consider as being diff --git a/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean b/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean index f7bb524702e5c..a5bf157bf3564 100644 --- a/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean +++ b/Mathlib/CategoryTheory/Bicategory/Functor/Prelax.lean @@ -76,10 +76,6 @@ def mkOfHomPrefunctors (F : B → C) (F' : (a : B) → (b : B) → Prefunctor (a map {a b} := (F' a b).obj map₂ {a b} := (F' a b).map --- Porting note: deleted syntactic tautologies `toPrefunctor_eq_coe : F.toPrefunctor = F` --- and `to_prefunctor_obj : (F : Prefunctor B C).obj = F.obj` --- and `to_prefunctor_map` - /-- The identity lax prefunctor. -/ @[simps] def id (B : Type u₁) [Quiver.{v₁ + 1} B] [∀ a b : B, Quiver.{w₁ + 1} (a ⟶ b)] : diff --git a/Mathlib/CategoryTheory/Category/Cat/AsSmall.lean b/Mathlib/CategoryTheory/Category/Cat/AsSmall.lean new file mode 100644 index 0000000000000..f65cd41c8bb6d --- /dev/null +++ b/Mathlib/CategoryTheory/Category/Cat/AsSmall.lean @@ -0,0 +1,34 @@ +/- +Copyright (c) 2024 Jakob von Raumer. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jakob von Raumer +-/ +import Mathlib.CategoryTheory.Category.Cat +import Mathlib.CategoryTheory.Category.ULift + +/-! +# Functorially embedding `Cat` into the category of small categories + +There is a canonical functor `asSmallFunctor` between the category of categories of any size and +any larger category of small categories. + +## Future Work + +Show that `asSmallFunctor` is faithful. +-/ + +universe w v u + +namespace CategoryTheory + +namespace Cat + +/-- Assigning to each category `C` the small category `AsSmall C` induces a functor `Cat ⥤ Cat`. -/ +@[simps] +def asSmallFunctor : Cat.{v, u} ⥤ Cat.{max w v u, max w v u} where + obj C := .of <| AsSmall C + map F := AsSmall.down ⋙ F ⋙ AsSmall.up + +end Cat + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Category/ULift.lean b/Mathlib/CategoryTheory/Category/ULift.lean index f70fe083dec2f..6a7b80e9fb347 100644 --- a/Mathlib/CategoryTheory/Category/ULift.lean +++ b/Mathlib/CategoryTheory/Category/ULift.lean @@ -174,6 +174,16 @@ def AsSmall.down : AsSmall C ⥤ C where obj X := ULift.down X map f := f.down +@[reassoc] +theorem down_comp {X Y Z : AsSmall C} (f : X ⟶ Y) (g : Y ⟶ Z) : (f ≫ g).down = f.down ≫ g.down := + rfl + +@[simp] +theorem eqToHom_down {X Y : AsSmall C} (h : X = Y) : + (eqToHom h).down = eqToHom (congrArg ULift.down h) := by + subst h + rfl + /-- The equivalence between `C` and `AsSmall C`. -/ @[simps] def AsSmall.equiv : C ≌ AsSmall C where diff --git a/Mathlib/CategoryTheory/Closed/Enrichment.lean b/Mathlib/CategoryTheory/Closed/Enrichment.lean index 1d263f92528ed..d0cedeb852160 100644 --- a/Mathlib/CategoryTheory/Closed/Enrichment.lean +++ b/Mathlib/CategoryTheory/Closed/Enrichment.lean @@ -15,9 +15,9 @@ where the hom-object is given by the internal hom (coming from the closed struct We use `scoped instance` to avoid potential issues where `C` may also have a `C`-category structure coming from another source (e.g. the type of simplicial sets `SSet.{v}` has an instance of `EnrichedCategory SSet.{v}` as a category of simplicial objects; -see `AlgebraicTopology/SimplicialCategory/SimplicialObject`). +see `Mathlib/AlgebraicTopology/SimplicialCategory/SimplicialObject.lean`). -All structure field values are defined in `Closed/Monoidal`. +All structure field values are defined in `Mathlib/CategoryTheory/Closed/Monoidal.lean`. -/ diff --git a/Mathlib/CategoryTheory/Comma/Over.lean b/Mathlib/CategoryTheory/Comma/Over.lean index 9f9609c579450..8b852e7627a5b 100644 --- a/Mathlib/CategoryTheory/Comma/Over.lean +++ b/Mathlib/CategoryTheory/Comma/Over.lean @@ -852,7 +852,8 @@ def ofDiagEquivalence (X : T × T) : /-- A version of `StructuredArrow.ofDiagEquivalence` with the roles of the first and second projection swapped. -/ -def ofDiagEquivalence' (X : T × T) : +-- noncomputability is only for performance +noncomputable def ofDiagEquivalence' (X : T × T) : StructuredArrow X (Functor.diag _) ≌ StructuredArrow X.1 (Under.forget X.2) := (ofDiagEquivalence X).trans <| (ofStructuredArrowProjEquivalence (𝟭 T) X.1 X.2).trans <| @@ -919,7 +920,8 @@ def ofDiagEquivalence (X : T × T) : /-- A version of `CostructuredArrow.ofDiagEquivalence` with the roles of the first and second projection swapped. -/ -def ofDiagEquivalence' (X : T × T) : +-- noncomputability is only for performance +noncomputable def ofDiagEquivalence' (X : T × T) : CostructuredArrow (Functor.diag _) X ≌ CostructuredArrow (Over.forget X.2) X.1 := (ofDiagEquivalence X).trans <| (ofCostructuredArrowProjEquivalence (𝟭 T) X.1 X.2).trans <| diff --git a/Mathlib/CategoryTheory/Extensive.lean b/Mathlib/CategoryTheory/Extensive.lean index 87488121b4c56..dd21c2f557352 100644 --- a/Mathlib/CategoryTheory/Extensive.lean +++ b/Mathlib/CategoryTheory/Extensive.lean @@ -102,7 +102,7 @@ theorem FinitaryExtensive.vanKampen [FinitaryExtensive C] {F : Discrete WalkingP have : F = pair X Y := by apply Functor.hext · rintro ⟨⟨⟩⟩ <;> rfl - · rintro ⟨⟨⟩⟩ ⟨j⟩ ⟨⟨rfl : _ = j⟩⟩ <;> simp + · rintro ⟨⟨⟩⟩ ⟨j⟩ ⟨⟨rfl : _ = j⟩⟩ <;> simp [X, Y] clear_value X Y subst this exact FinitaryExtensive.van_kampen' c hc @@ -491,7 +491,7 @@ lemma FinitaryPreExtensive.hasPullbacks_of_is_coproduct [FinitaryPreExtensive C] let e' : c.pt ≅ f i ⨿ (∐ fun j : ({i}ᶜ : Set ι) ↦ f j) := hc.coconePointUniqueUpToIso (getColimitCocone _).2 ≪≫ e have : coprod.inl ≫ e'.inv = c.ι.app ⟨i⟩ := by - simp only [e', Iso.trans_inv, coprod.desc_comp, colimit.ι_desc, BinaryCofan.mk_pt, + simp only [e, e', Iso.trans_inv, coprod.desc_comp, colimit.ι_desc, BinaryCofan.mk_pt, BinaryCofan.ι_app_left, BinaryCofan.mk_inl] exact colimit.comp_coconePointUniqueUpToIso_inv _ _ clear_value e' diff --git a/Mathlib/CategoryTheory/GlueData.lean b/Mathlib/CategoryTheory/GlueData.lean index 936283e96bec5..5f09d792ec41d 100644 --- a/Mathlib/CategoryTheory/GlueData.lean +++ b/Mathlib/CategoryTheory/GlueData.lean @@ -443,7 +443,7 @@ def GlueData'.t'' (D : GlueData' C) (i j k : D.J) : else haveI := Ne.symm hij pullback.map _ _ _ _ (eqToHom (by aesop)) (eqToHom (by rw [dif_neg hik])) - (eqToHom (by aesop)) (by aesop) (by delta f'; aesop) ≫ + (eqToHom (by aesop)) (by delta f'; aesop) (by delta f'; aesop) ≫ D.t' i j k hij hik hjk ≫ pullback.map _ _ _ _ (eqToHom (by aesop)) (eqToHom (by aesop)) (eqToHom (by aesop)) (by delta f'; aesop) (by delta f'; aesop) diff --git a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean index 3950b5d3d1b1a..d1c4c259169b5 100644 --- a/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean +++ b/Mathlib/CategoryTheory/GradedObject/Trifunctor.lean @@ -345,7 +345,7 @@ noncomputable def isColimitCofan₃MapBifunctor₁₂BifunctorMapObj (j : J) : 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, c₁₂'', Z] + dsimp [Cofan.inj, c₁₂'', Z, p'] rw [comp_id, Functor.map_id, id_comp] rfl @@ -523,7 +523,7 @@ noncomputable def isColimitCofan₃MapBifunctorBifunctor₂₃MapObj (j : J) : 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, c₂₃''] + dsimp [Cofan.inj, c₂₃'', Z, p', e] rw [comp_id, id_comp] rfl diff --git a/Mathlib/CategoryTheory/Grothendieck.lean b/Mathlib/CategoryTheory/Grothendieck.lean index eeffded6b2bbb..78495117317b8 100644 --- a/Mathlib/CategoryTheory/Grothendieck.lean +++ b/Mathlib/CategoryTheory/Grothendieck.lean @@ -3,7 +3,7 @@ Copyright (c) 2020 Kim Morrison. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kim Morrison, Sina Hazratpour -/ -import Mathlib.CategoryTheory.Category.Cat +import Mathlib.CategoryTheory.Category.Cat.AsSmall import Mathlib.CategoryTheory.Elements import Mathlib.CategoryTheory.Comma.Over @@ -38,12 +38,13 @@ See also `CategoryTheory.Functor.Elements` for the category of elements of funct -/ -universe u +universe w u v u₁ v₁ u₂ v₂ namespace CategoryTheory -variable {C D : Type*} [Category C] [Category D] -variable (F : C ⥤ Cat) +variable {C : Type u} [Category.{v} C] +variable {D : Type u₁} [Category.{v₁} D] +variable (F : C ⥤ Cat.{v₂, u₂}) /-- The Grothendieck construction (often written as `∫ F` in mathematics) for a functor `F : C ⥤ Cat` @@ -229,9 +230,65 @@ theorem map_comp_eq (α : F ⟶ G) (β : G ⟶ H) : if possible, and we should prefer `map_comp_iso` to `map_comp_eq` whenever we can. -/ def mapCompIso (α : F ⟶ G) (β : G ⟶ H) : map (α ≫ β) ≅ map α ⋙ map β := eqToIso (map_comp_eq α β) -end +variable (F) -universe v +/-- The inverse functor to build the equivalence `compAsSmallFunctorEquivalence`. -/ +@[simps] +def compAsSmallFunctorEquivalenceInverse : + Grothendieck F ⥤ Grothendieck (F ⋙ Cat.asSmallFunctor.{w}) where + obj X := ⟨X.base, AsSmall.up.obj X.fiber⟩ + map f := ⟨f.base, AsSmall.up.map f.fiber⟩ + +/-- The functor to build the equivalence `compAsSmallFunctorEquivalence`. -/ +@[simps] +def compAsSmallFunctorEquivalenceFunctor : + Grothendieck (F ⋙ Cat.asSmallFunctor.{w}) ⥤ Grothendieck F where + obj X := ⟨X.base, AsSmall.down.obj X.fiber⟩ + map f := ⟨f.base, AsSmall.down.map f.fiber⟩ + map_id _ := by apply Grothendieck.ext <;> simp + map_comp _ _ := by apply Grothendieck.ext <;> simp [down_comp] + +/-- Taking the Grothendieck construction on `F ⋙ asSmallFunctor`, where +`asSmallFunctor : Cat ⥤ Cat` is the functor which turns each category into a small category of a +(potentiall) larger universe, is equivalent to the Grothendieck construction on `F` itself. -/ +@[simps] +def compAsSmallFunctorEquivalence : + Grothendieck (F ⋙ Cat.asSmallFunctor.{w}) ≌ Grothendieck F where + functor := compAsSmallFunctorEquivalenceFunctor F + inverse := compAsSmallFunctorEquivalenceInverse F + counitIso := Iso.refl _ + unitIso := Iso.refl _ + +/-- Mapping a Grothendieck construction along the whiskering of any natural transformation +`α : F ⟶ G` with the functor `asSmallFunctor : Cat ⥤ Cat` is naturally isomorphic to conjugating +`map α` with the equivalence between `Grothendieck (F ⋙ asSmallFunctor)` and `Grothendieck F`. -/ +def mapWhiskerRightAsSmallFunctor (α : F ⟶ G) : + map (whiskerRight α Cat.asSmallFunctor.{w}) ≅ + (compAsSmallFunctorEquivalence F).functor ⋙ map α ⋙ + (compAsSmallFunctorEquivalence G).inverse := + NatIso.ofComponents + (fun X => Iso.refl _) + (fun f => by + fapply Grothendieck.ext + · simp [compAsSmallFunctorEquivalenceInverse] + · simp only [compAsSmallFunctorEquivalence_functor, compAsSmallFunctorEquivalence_inverse, + Functor.comp_obj, compAsSmallFunctorEquivalenceInverse_obj_base, map_obj_base, + compAsSmallFunctorEquivalenceFunctor_obj_base, Cat.asSmallFunctor_obj, Cat.of_α, + Iso.refl_hom, Functor.comp_map, comp_base, id_base, + compAsSmallFunctorEquivalenceInverse_map_base, map_map_base, + compAsSmallFunctorEquivalenceFunctor_map_base, Cat.asSmallFunctor_map, map_obj_fiber, + whiskerRight_app, AsSmall.down_obj, AsSmall.up_obj_down, + compAsSmallFunctorEquivalenceInverse_obj_fiber, + compAsSmallFunctorEquivalenceFunctor_obj_fiber, comp_fiber, map_map_fiber, + AsSmall.down_map, down_comp, eqToHom_down, AsSmall.up_map_down, Functor.map_comp, + eqToHom_map, id_fiber, Category.assoc, eqToHom_trans_assoc, + compAsSmallFunctorEquivalenceInverse_map_fiber, + compAsSmallFunctorEquivalenceFunctor_map_fiber, eqToHom_comp_iff, comp_eqToHom_iff] + simp only [eqToHom_trans_assoc, Category.assoc, conj_eqToHom_iff_heq'] + rw [G.map_id] + simp ) + +end /-- The Grothendieck construction as a functor from the functor category `E ⥤ Cat` to the over category `Over E`. -/ @@ -245,8 +302,6 @@ def functor {E : Cat.{v,u}} : (E ⥤ Cat.{v,u}) ⥤ Over (T := Cat.{v,u}) E wher simp [Grothendieck.map_comp_eq α β] rfl -universe w - variable (G : C ⥤ Type w) /-- Auxiliary definition for `grothendieckTypeToCat`, to speed up elaboration. -/ diff --git a/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean index aa1af4a9269f3..29b94beac78e3 100644 --- a/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean +++ b/Mathlib/CategoryTheory/Idempotents/FunctorCategories.lean @@ -70,14 +70,14 @@ instance functor_category_isIdempotentComplete [IsIdempotentComplete C] : let e : F ⟶ Y := { app := fun j => equalizer.lift (p.app j) (by simpa only [comp_id] using (congr_app hp j).symm) - naturality := fun j j' φ => equalizer.hom_ext (by simp) } + naturality := fun j j' φ => equalizer.hom_ext (by simp [Y]) } use Y, i, e constructor · ext j dsimp rw [assoc, equalizer.lift_ι, ← equalizer.condition, id_comp, comp_id] · ext j - simp + simp [Y, i, e] namespace KaroubiFunctorCategoryEmbedding variable {J C} diff --git a/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean b/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean index dd4c4c861c62c..1496b467c1f8a 100644 --- a/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean +++ b/Mathlib/CategoryTheory/Limits/ConcreteCategory/WithAlgebraicStructures.lean @@ -4,12 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jujian Zhang -/ import Mathlib.CategoryTheory.Limits.ConcreteCategory.Basic -import Mathlib.Algebra.Module.LinearMap.Defs +import Mathlib.Algebra.Category.ModuleCat.Basic import Mathlib.Tactic.CategoryTheory.Elementwise /-! - -# Colimits in concrete categories with algebraic structures +# Colimits in ModuleCat Let `C` be a concrete category and `F : J ⥤ C` a filtered diagram in `C`. We discuss some results about `colimit F` when objects and morphisms in `C` have some algebraic structures. @@ -25,6 +24,11 @@ about `colimit F` when objects and morphisms in `C` have some algebraic structur and `x : Fᵢ` we have `r • x = 0` implies `x = 0`, then if `r • x = 0` for `x : colimit F`, then `x = 0`. +## Implementation details + +For now, we specialize our results to `C = ModuleCat R`, which is the only place they are used. +In the future they might be generalized by assuming a `HasForget₂ C (ModuleCat R)` instance, +plus assertions that the module structures induced by `HasForget₂` coincide. -/ universe t w v u r @@ -33,20 +37,20 @@ open CategoryTheory namespace CategoryTheory.Limits.Concrete -attribute [local instance] ConcreteCategory.instFunLike ConcreteCategory.hasCoeToSort - -variable {C : Type u} [Category.{v} C] [ConcreteCategory.{max t w} C] {J : Type w} [Category.{r} J] +variable (R : Type*) [Ring R] {J : Type w} [Category.{r} J] section zero theorem colimit_rep_eq_zero - (F : J ⥤ C) [PreservesColimit F (forget C)] [IsFiltered J] - [∀ c : C, Zero c] [∀ {c c' : C}, ZeroHomClass (c ⟶ c') c c'] [HasColimit F] - (j : J) (x : F.obj j) (hx : colimit.ι F j x = 0) : - ∃ (j' : J) (i : j ⟶ j'), F.map i x = 0 := by - rw [show 0 = colimit.ι F j 0 by simp, colimit_rep_eq_iff_exists] at hx + (F : J ⥤ ModuleCat.{max t w} R) [PreservesColimit F (forget (ModuleCat R))] [IsFiltered J] + [HasColimit F] (j : J) (x : F.obj j) (hx : colimit.ι F j x = 0) : + ∃ (j' : J) (i : j ⟶ j'), (F.map i).hom x = 0 := by + -- Break the abstraction barrier between homs and functions for `colimit_rep_eq_iff_exists`. + have : ∀ (X Y : ModuleCat R) (f : X ⟶ Y), + DFunLike.coe f.hom = DFunLike.coe (self := ConcreteCategory.instFunLike) f := fun _ _ _ => rfl + rw [show 0 = colimit.ι F j 0 by simp, this, colimit_rep_eq_iff_exists] at hx obtain ⟨j', i, y, g⟩ := hx - exact ⟨j', i, g ▸ by simp⟩ + exact ⟨j', i, g ▸ by simp [← this]⟩ end zero @@ -57,23 +61,25 @@ if `r` has no zero smul divisors for all small-enough sections, then `r` has no in the colimit. -/ lemma colimit_no_zero_smul_divisor - (F : J ⥤ C) [PreservesColimit F (forget C)] [IsFiltered J] [HasColimit F] - (R : Type*) [Semiring R] - [∀ c : C, AddCommMonoid c] [∀ c : C, Module R c] - [∀ {c c' : C}, LinearMapClass (c ⟶ c') R c c'] + (F : J ⥤ ModuleCat.{max t w} R) [PreservesColimit F (forget (ModuleCat R))] + [IsFiltered J] [HasColimit F] (r : R) (H : ∃ (j' : J), ∀ (j : J) (_ : j' ⟶ j), ∀ (c : F.obj j), r • c = 0 → c = 0) - (x : (forget C).obj (colimit F)) (hx : r • x = 0) : x = 0 := by + (x : (forget (ModuleCat R)).obj (colimit F)) (hx : r • x = 0) : x = 0 := by + + -- Break the abstraction barrier between homs and functions for `Concrete.colimit_exists_rep`. + have : ∀ (X Y : ModuleCat R) (f : X ⟶ Y), + DFunLike.coe f.hom = DFunLike.coe (self := ConcreteCategory.instFunLike) f := fun _ _ _ => rfl classical obtain ⟨j, x, rfl⟩ := Concrete.colimit_exists_rep F x - rw [← map_smul] at hx + rw [← this, ← map_smul (colimit.ι F j).hom] at hx obtain ⟨j', i, h⟩ := Concrete.colimit_rep_eq_zero (hx := hx) obtain ⟨j'', H⟩ := H - simpa [elementwise_of% (colimit.w F), map_zero] using congr(colimit.ι F _ + simpa [elementwise_of% (colimit.w F), this, map_zero] using congr(colimit.ι F _ $(H (IsFiltered.sup {j, j', j''} { ⟨j, j', by simp, by simp, i⟩ }) (IsFiltered.toSup _ _ <| by simp) (F.map (IsFiltered.toSup _ _ <| by simp) x) (by rw [← IsFiltered.toSup_commutes (f := i) (mY := by simp) (mf := by simp), F.map_comp, - comp_apply, ← map_smul, ← map_smul, h, map_zero]))) + ModuleCat.comp_apply, ← map_smul, ← map_smul, h, map_zero]))) end module diff --git a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean index 353032099523c..84ff0c9c14b61 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/LimitsOfProductsAndEqualizers.lean @@ -166,19 +166,19 @@ lemma preservesLimit_of_preservesEqualizers_and_product : let I := equalizer s t let i : I ⟶ P := equalizer.ι s t apply preservesLimit_of_preserves_limit_cone - (buildIsLimit s t (by simp [s]) (by simp [t]) (limit.isLimit _) (limit.isLimit _) - (limit.isLimit _)) + (buildIsLimit s t (by simp [P, s]) (by simp [P, t]) (limit.isLimit _) + (limit.isLimit _) (limit.isLimit _)) apply IsLimit.ofIsoLimit (buildIsLimit _ _ _ _ _ _ _) _ · exact Fan.mk _ fun j => G.map (Pi.π _ j) · exact Fan.mk (G.obj Q) fun f => G.map (Pi.π _ f) · apply G.map s · apply G.map t · intro f - dsimp [s, Fan.mk] + dsimp [P, Q, s, Fan.mk] simp only [← G.map_comp, limit.lift_π] congr · intro f - dsimp [t, Fan.mk] + dsimp [P, Q, t, Fan.mk] simp only [← G.map_comp, limit.lift_π] apply congrArg G.map dsimp @@ -191,7 +191,7 @@ lemma preservesLimit_of_preservesEqualizers_and_product : · apply isLimitForkMapOfIsLimit apply equalizerIsEqualizer · refine Cones.ext (Iso.refl _) ?_ - intro j; dsimp; simp + intro j; dsimp [P, Q, I, i]; simp -- See note [dsimp, simp]. end @@ -382,8 +382,8 @@ lemma preservesColimit_of_preservesCoequalizers_and_coproduct : let I := coequalizer s t let i : P ⟶ I := coequalizer.π s t apply preservesColimit_of_preserves_colimit_cocone - (buildIsColimit s t (by simp [s]) (by simp [t]) (colimit.isColimit _) (colimit.isColimit _) - (colimit.isColimit _)) + (buildIsColimit s t (by simp [P, s]) (by simp [P, t]) (colimit.isColimit _) + (colimit.isColimit _) (colimit.isColimit _)) apply IsColimit.ofIsoColimit (buildIsColimit _ _ _ _ _ _ _) _ · refine Cofan.mk (G.obj Q) fun j => G.map ?_ apply Sigma.ι _ j @@ -392,11 +392,11 @@ lemma preservesColimit_of_preservesCoequalizers_and_coproduct : · apply G.map s · apply G.map t · intro f - dsimp [s, Cofan.mk] + dsimp [P, Q, s, Cofan.mk] simp only [← G.map_comp, colimit.ι_desc] congr · intro f - dsimp [t, Cofan.mk] + dsimp [P, Q, t, Cofan.mk] simp only [← G.map_comp, colimit.ι_desc] dsimp · refine Cofork.ofπ (G.map i) ?_ @@ -409,7 +409,7 @@ lemma preservesColimit_of_preservesCoequalizers_and_coproduct : apply coequalizerIsCoequalizer refine Cocones.ext (Iso.refl _) ?_ intro j - dsimp + dsimp [P, Q, I, i] simp -- See note [dsimp, simp]. diff --git a/Mathlib/CategoryTheory/Limits/Constructions/Pullbacks.lean b/Mathlib/CategoryTheory/Limits/Constructions/Pullbacks.lean index e6c2252ce3d8d..577fbad322d22 100644 --- a/Mathlib/CategoryTheory/Limits/Constructions/Pullbacks.lean +++ b/Mathlib/CategoryTheory/Limits/Constructions/Pullbacks.lean @@ -31,7 +31,9 @@ theorem hasLimit_cospan_of_hasLimit_pair_of_hasLimit_parallelPair {C : Type u} [ let e := equalizer.ι (π₁ ≫ f) (π₂ ≫ g) HasLimit.mk { cone := - PullbackCone.mk (e ≫ π₁) (e ≫ π₂) <| by rw [Category.assoc, equalizer.condition]; simp + PullbackCone.mk (e ≫ π₁) (e ≫ π₂) <| by + rw [Category.assoc, equalizer.condition] + simp [e] isLimit := PullbackCone.IsLimit.mk _ (fun s => equalizer.lift (prod.lift (s.π.app WalkingCospan.left) (s.π.app WalkingCospan.right)) <| by diff --git a/Mathlib/CategoryTheory/Limits/Filtered.lean b/Mathlib/CategoryTheory/Limits/Filtered.lean index 536b215594402..f30d4ab31ca83 100644 --- a/Mathlib/CategoryTheory/Limits/Filtered.lean +++ b/Mathlib/CategoryTheory/Limits/Filtered.lean @@ -17,7 +17,7 @@ Furthermore, we define the type classes `HasCofilteredLimitsOfSize` and `HasFilt -/ -universe w' w v u +universe w' w w₂' w₂ v u noncomputable section @@ -103,6 +103,32 @@ instance (priority := 100) hasColimitsOfShape_of_has_filtered_colimits HasColimitsOfShape I C := HasFilteredColimitsOfSize.HasColimitsOfShape _ +lemma hasCofilteredLimitsOfSize_of_univLE [UnivLE.{w, w₂}] [UnivLE.{w', w₂'}] + [HasCofilteredLimitsOfSize.{w₂', w₂} C] : + HasCofilteredLimitsOfSize.{w', w} C where + HasLimitsOfShape J := + haveI := IsCofiltered.of_equivalence ((ShrinkHoms.equivalence.{w₂'} J).trans <| + Shrink.equivalence.{w₂} (ShrinkHoms.{w} J)) + hasLimitsOfShape_of_equivalence ((ShrinkHoms.equivalence.{w₂'} J).trans <| + Shrink.equivalence.{w₂} (ShrinkHoms.{w} J)).symm + +lemma hasCofilteredLimitsOfSize_shrink [HasCofilteredLimitsOfSize.{max w' w₂', max w w₂} C] : + HasCofilteredLimitsOfSize.{w', w} C := + hasCofilteredLimitsOfSize_of_univLE.{w', w, max w' w₂', max w w₂} + +lemma hasFilteredColimitsOfSize_of_univLE [UnivLE.{w, w₂}] [UnivLE.{w', w₂'}] + [HasFilteredColimitsOfSize.{w₂', w₂} C] : + HasFilteredColimitsOfSize.{w', w} C where + HasColimitsOfShape J := + haveI := IsFiltered.of_equivalence ((ShrinkHoms.equivalence.{w₂'} J).trans <| + Shrink.equivalence.{w₂} (ShrinkHoms.{w} J)) + hasColimitsOfShape_of_equivalence ((ShrinkHoms.equivalence.{w₂'} J).trans <| + Shrink.equivalence.{w₂} (ShrinkHoms.{w} J)).symm + +lemma hasFilteredColimitsOfSize_shrink [HasFilteredColimitsOfSize.{max w' w₂', max w w₂} C] : + HasFilteredColimitsOfSize.{w', w} C := + hasFilteredColimitsOfSize_of_univLE.{w', w, max w' w₂', max w w₂} + end Limits end CategoryTheory diff --git a/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesProduct.lean b/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesProduct.lean index ac195d5acac16..790a96b3416e6 100644 --- a/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesProduct.lean +++ b/Mathlib/CategoryTheory/Limits/FilteredColimitCommutesProduct.lean @@ -136,9 +136,9 @@ theorem Types.isIso_colimitPointwiseProductToProductColimit (F : ∀ i, I i ⥤ let yk' : (pointwiseProduct F).obj k := (pointwiseProduct F).map (IsFiltered.rightToMax ky ky') yk₀' obtain rfl : y = colimit.ι (pointwiseProduct F) k yk := by - simp only [yk, Types.Colimit.w_apply', hyk₀] + simp only [k, yk, Types.Colimit.w_apply', hyk₀] obtain rfl : y' = colimit.ι (pointwiseProduct F) k yk' := by - simp only [yk', Types.Colimit.w_apply', hyk₀'] + simp only [k, yk', Types.Colimit.w_apply', hyk₀'] dsimp only [pointwiseProduct_obj] at yk yk' have hch : ∀ (s : α), ∃ (i' : I s) (hi' : k s ⟶ i'), (F s).map hi' (Pi.π (fun s => (F s).obj (k s)) s yk) = diff --git a/Mathlib/CategoryTheory/Limits/HasLimits.lean b/Mathlib/CategoryTheory/Limits/HasLimits.lean index febff5598358d..744fd90f39333 100644 --- a/Mathlib/CategoryTheory/Limits/HasLimits.lean +++ b/Mathlib/CategoryTheory/Limits/HasLimits.lean @@ -992,11 +992,10 @@ end variable {G : J ⥤ C} (α : F ⟶ G) --- @[reassoc (attr := simp)] Porting note: now simp can prove these @[reassoc] theorem colimit.ι_map (j : J) : colimit.ι F j ≫ colim.map α = α.app j ≫ colimit.ι G j := by simp -@[simp] -- Porting note: proof adjusted to account for @[simps] on all fields of colim +@[simp] theorem colimit.map_desc (c : Cocone G) : colimMap α ≫ colimit.desc G c = colimit.desc F ((Cocones.precompose α).obj c) := by ext j @@ -1125,8 +1124,7 @@ def IsColimit.op {t : Cocone F} (P : IsColimit t) : IsLimit t.op where -/ def IsLimit.unop {t : Cone F.op} (P : IsLimit t) : IsColimit t.unop where desc s := (P.lift s.op).unop - fac s j := congrArg Quiver.Hom.unop (P.fac s.op (Opposite.op j)) - -- Porting note: thinks `op j` is `IsLimit.op j` + fac s j := congrArg Quiver.Hom.unop (P.fac s.op (.op j)) uniq s m w := by dsimp rw [← P.uniq s.op m.op] @@ -1140,8 +1138,7 @@ def IsLimit.unop {t : Cone F.op} (P : IsLimit t) : IsColimit t.unop where -/ def IsColimit.unop {t : Cocone F.op} (P : IsColimit t) : IsLimit t.unop where lift s := (P.desc s.op).unop - fac s j := congrArg Quiver.Hom.unop (P.fac s.op (Opposite.op j)) - -- Porting note: thinks `op j` is `IsLimit.op j` + fac s j := congrArg Quiver.Hom.unop (P.fac s.op (.op j)) uniq s m w := by dsimp rw [← P.uniq s.op m.op] diff --git a/Mathlib/CategoryTheory/Limits/Opposites.lean b/Mathlib/CategoryTheory/Limits/Opposites.lean index 493dec55ff8dc..eeffcd5c0cf60 100644 --- a/Mathlib/CategoryTheory/Limits/Opposites.lean +++ b/Mathlib/CategoryTheory/Limits/Opposites.lean @@ -570,7 +570,8 @@ instance : HasProduct (op <| Z ·) := hasLimitOfIso def Cofan.op (c : Cofan Z) : Fan (op <| Z ·) := Fan.mk _ (fun a ↦ (c.inj a).op) /-- If a `Cofan` is colimit, then its opposite is limit. -/ -def Cofan.IsColimit.op {c : Cofan Z} (hc : IsColimit c) : IsLimit c.op := by +-- noncomputability is just for performance (compilation takes a while) +noncomputable def Cofan.IsColimit.op {c : Cofan Z} (hc : IsColimit c) : IsLimit c.op := by let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _) refine IsLimit.ofIsoLimit ((IsLimit.postcomposeInvEquiv e _).2 @@ -666,7 +667,8 @@ instance : HasCoproduct (op <| Z ·) := hasColimitOfIso def Fan.op (f : Fan Z) : Cofan (op <| Z ·) := Cofan.mk _ (fun a ↦ (f.proj a).op) /-- If a `Fan` is limit, then its opposite is colimit. -/ -def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by +-- noncomputability is just for performance (compilation takes a while) +noncomputable def Fan.IsLimit.op {f : Fan Z} (hf : IsLimit f) : IsColimit f.op := by let e : Discrete.functor (Opposite.op <| Z ·) ≅ (Discrete.opposite α).inverse ⋙ (Discrete.functor Z).op := Discrete.natIso (fun _ ↦ Iso.refl _) refine IsColimit.ofIsoColimit ((IsColimit.precomposeHomEquiv e _).2 @@ -950,6 +952,7 @@ def unopOp {X Y Z : Cᵒᵖ} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) /-- A pushout cone is a colimit cocone if and only if the corresponding pullback cone in the opposite category is a limit cone. -/ +noncomputable -- just for performance; compilation takes several seconds def isColimitEquivIsLimitOp {X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : IsColimit c ≃ IsLimit c.op := by apply equivOfSubsingletonOfSubsingleton @@ -963,6 +966,7 @@ def isColimitEquivIsLimitOp {X Y Z : C} {f : X ⟶ Y} {g : X ⟶ Z} (c : Pushout /-- A pushout cone is a colimit cocone in `Cᵒᵖ` if and only if the corresponding pullback cone in `C` is a limit cone. -/ +noncomputable -- just for performance; compilation takes several seconds def isColimitEquivIsLimitUnop {X Y Z : Cᵒᵖ} {f : X ⟶ Y} {g : X ⟶ Z} (c : PushoutCocone f g) : IsColimit c ≃ IsLimit c.unop := by apply equivOfSubsingletonOfSubsingleton diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean index 6f15d54ba6cac..e9b74760f9f31 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Shapes/Products.lean @@ -157,4 +157,18 @@ instance : IsIso (sigmaComparison G f) := by end +/-- If `F` preserves the limit of every `Discrete.functor f`, it preserves all limits of shape +`Discrete J`. -/ +lemma preservesLimitsOfShape_of_discrete (F : C ⥤ D) + [∀ (f : J → C), PreservesLimit (Discrete.functor f) F] : + PreservesLimitsOfShape (Discrete J) F where + preservesLimit := preservesLimit_of_iso_diagram F (Discrete.natIsoFunctor).symm + +/-- If `F` preserves the colimit of every `Discrete.functor f`, it preserves all colimits of shape +`Discrete J`. -/ +lemma preservesColimitsOfShape_of_discrete (F : C ⥤ D) + [∀ (f : J → C), PreservesColimit (Discrete.functor f) F] : + PreservesColimitsOfShape (Discrete J) F where + preservesColimit := preservesColimit_of_iso_diagram F (Discrete.natIsoFunctor).symm + end CategoryTheory.Limits diff --git a/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean b/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean index 7861c1e682600..6c02b797dda67 100644 --- a/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean +++ b/Mathlib/CategoryTheory/Limits/Preserves/Yoneda.lean @@ -23,7 +23,7 @@ pointwise. ## See also There is also a relative version of this statement where `F : J ⥤ Over A` for some presheaf -`A`, see `CategoryTheory.Comma.Presheaf.Colimit`. +`A`, see `Mathlib.CategoryTheory.Comma.Presheaf.Colimit`. -/ diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean b/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean index dfe5ff42f7453..29f15f3221a2d 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Biproducts.lean @@ -288,7 +288,7 @@ def whiskerToCocone {f : J → C} (c : Bicone f) (g : K ≃ J) : Cocones.ext (Iso.refl _) (by aesop_cat) /-- Whiskering a bicone with an equivalence between types preserves being a bilimit bicone. -/ -def whiskerIsBilimitIff {f : J → C} (c : Bicone f) (g : K ≃ J) : +noncomputable def whiskerIsBilimitIff {f : J → C} (c : Bicone f) (g : K ≃ J) : (c.whisker g).IsBilimit ≃ c.IsBilimit := by refine equivOfSubsingletonOfSubsingleton (fun hc => ⟨?_, ?_⟩) fun hc => ⟨?_, ?_⟩ · let this := IsLimit.ofIsoLimit hc.isLimit (Bicone.whiskerToCone c g) diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean index f03cd551569a5..202f266d2d66f 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Kernels.lean @@ -200,6 +200,29 @@ lemma KernelFork.IsLimit.isIso_ι {X Y : C} {f : X ⟶ Y} (c : KernelFork f) infer_instance exact IsIso.of_isIso_comp_left e.inv c.ι +/-- If `c` is a limit kernel fork for `g : X ⟶ Y`, `e : X ≅ X'` and `g' : X' ⟶ Y` is a morphism, +then there is a limit kernel fork for `g'` with the same point as `c` if for any +morphism `φ : W ⟶ X`, there is an equivalence `φ ≫ g = 0 ↔ φ ≫ e.hom ≫ g' = 0`. -/ +def KernelFork.isLimitOfIsLimitOfIff {X Y : C} {g : X ⟶ Y} {c : KernelFork g} (hc : IsLimit c) + {X' Y' : C} (g' : X' ⟶ Y') (e : X ≅ X') + (iff : ∀ ⦃W : C⦄ (φ : W ⟶ X), φ ≫ g = 0 ↔ φ ≫ e.hom ≫ g' = 0) : + IsLimit (KernelFork.ofι (f := g') (c.ι ≫ e.hom) (by simp [← iff])) := + KernelFork.IsLimit.ofι _ _ + (fun s hs ↦ hc.lift (KernelFork.ofι (ι := s ≫ e.inv) + (by rw [iff, Category.assoc, Iso.inv_hom_id_assoc, hs]))) + (fun s hs ↦ by simp [← cancel_mono e.inv]) + (fun s hs m hm ↦ Fork.IsLimit.hom_ext hc (by simpa [← cancel_mono e.hom] using hm)) + +/-- If `c` is a limit kernel fork for `g : X ⟶ Y`, and `g' : X ⟶ Y'` is a another morphism, +then there is a limit kernel fork for `g'` with the same point as `c` if for any +morphism `φ : W ⟶ X`, there is an equivalence `φ ≫ g = 0 ↔ φ ≫ g' = 0`. -/ +def KernelFork.isLimitOfIsLimitOfIff' {X Y : C} {g : X ⟶ Y} {c : KernelFork g} (hc : IsLimit c) + {Y' : C} (g' : X ⟶ Y') + (iff : ∀ ⦃W : C⦄ (φ : W ⟶ X), φ ≫ g = 0 ↔ φ ≫ g' = 0) : + IsLimit (KernelFork.ofι (f := g') c.ι (by simp [← iff])) := + IsLimit.ofIsoLimit (isLimitOfIsLimitOfIff hc g' (Iso.refl _) (by simpa using iff)) + (Fork.ext (Iso.refl _)) + end namespace KernelFork @@ -632,6 +655,29 @@ lemma CokernelCofork.IsColimit.isIso_π {X Y : C} {f : X ⟶ Y} (c : CokernelCof infer_instance exact IsIso.of_isIso_comp_right c.π e.hom +/-- If `c` is a colimit cokernel cofork for `f : X ⟶ Y`, `e : Y ≅ Y'` and `f' : X' ⟶ Y` is a +morphism, then there is a colimit cokernel cofork for `f'` with the same point as `c` if for any +morphism `φ : Y ⟶ W`, there is an equivalence `f ≫ φ = 0 ↔ f' ≫ e.hom ≫ φ = 0`. -/ +def CokernelCofork.isColimitOfIsColimitOfIff {X Y : C} {f : X ⟶ Y} {c : CokernelCofork f} + (hc : IsColimit c) {X' Y' : C} (f' : X' ⟶ Y') (e : Y' ≅ Y) + (iff : ∀ ⦃W : C⦄ (φ : Y ⟶ W), f ≫ φ = 0 ↔ f' ≫ e.hom ≫ φ = 0) : + IsColimit (CokernelCofork.ofπ (f := f') (e.hom ≫ c.π) (by simp [← iff])) := + CokernelCofork.IsColimit.ofπ _ _ + (fun s hs ↦ hc.desc (CokernelCofork.ofπ (π := e.inv ≫ s) + (by rw [iff, e.hom_inv_id_assoc, hs]))) + (fun s hs ↦ by simp [← cancel_epi e.inv]) + (fun s hs m hm ↦ Cofork.IsColimit.hom_ext hc (by simpa [← cancel_epi e.hom] using hm)) + +/-- If `c` is a colimit cokernel cofork for `f : X ⟶ Y`, and `f' : X' ⟶ Y is another +morphism, then there is a colimit cokernel cofork for `f'` with the same point as `c` if for any +morphism `φ : Y ⟶ W`, there is an equivalence `f ≫ φ = 0 ↔ f' ≫ φ = 0`. -/ +def CokernelCofork.isColimitOfIsColimitOfIff' {X Y : C} {f : X ⟶ Y} {c : CokernelCofork f} + (hc : IsColimit c) {X' : C} (f' : X' ⟶ Y) + (iff : ∀ ⦃W : C⦄ (φ : Y ⟶ W), f ≫ φ = 0 ↔ f' ≫ φ = 0) : + IsColimit (CokernelCofork.ofπ (f := f') c.π (by simp [← iff])) := + IsColimit.ofIsoColimit (isColimitOfIsColimitOfIff hc f' (Iso.refl _) (by simpa using iff)) + (Cofork.ext (Iso.refl _)) + end namespace CokernelCofork diff --git a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean index ed9bd8a77cbda..02cc099007693 100644 --- a/Mathlib/CategoryTheory/Limits/Shapes/Products.lean +++ b/Mathlib/CategoryTheory/Limits/Shapes/Products.lean @@ -653,12 +653,17 @@ abbrev HasCoproducts := variable {C} -theorem has_smallest_products_of_hasProducts [HasProducts.{w} C] : HasProducts.{0} C := fun J => - hasLimitsOfShape_of_equivalence (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w} J) ≌ _) +lemma hasProducts_shrink [HasProducts.{max w w'} C] : HasProducts.{w} C := fun J => + hasLimitsOfShape_of_equivalence (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w'} J) ≌ _) + +lemma hasCoproducts_shrink [HasCoproducts.{max w w'} C] : HasCoproducts.{w} C := fun J => + hasColimitsOfShape_of_equivalence (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w'} J) ≌ _) + +theorem has_smallest_products_of_hasProducts [HasProducts.{w} C] : HasProducts.{0} C := + hasProducts_shrink theorem has_smallest_coproducts_of_hasCoproducts [HasCoproducts.{w} C] : HasCoproducts.{0} C := - fun J => - hasColimitsOfShape_of_equivalence (Discrete.equivalence Equiv.ulift : Discrete (ULift.{w} J) ≌ _) + hasCoproducts_shrink theorem hasProducts_of_limit_fans (lf : ∀ {J : Type w} (f : J → C), Fan f) (lf_isLimit : ∀ {J : Type w} (f : J → C), IsLimit (lf f)) : HasProducts.{w} C := diff --git a/Mathlib/CategoryTheory/Limits/SmallComplete.lean b/Mathlib/CategoryTheory/Limits/SmallComplete.lean index 66ba7ba7e12d4..41ff160e8b730 100644 --- a/Mathlib/CategoryTheory/Limits/SmallComplete.lean +++ b/Mathlib/CategoryTheory/Limits/SmallComplete.lean @@ -61,10 +61,10 @@ instance (priority := 100) : Quiver.IsThin C := fun X Y => refine ⟨⟨Pi.lift, fun f k => f ≫ Pi.π _ k, ?_, ?_⟩⟩ · intro f ext k - simp + simp [yp] · intro f ext ⟨j⟩ - simp + simp [yp] · apply Cardinal.mk_le_of_injective _ · intro f exact ⟨_, _, f⟩ diff --git a/Mathlib/CategoryTheory/Limits/VanKampen.lean b/Mathlib/CategoryTheory/Limits/VanKampen.lean index 75e50cc0928fc..705c13f505a00 100644 --- a/Mathlib/CategoryTheory/Limits/VanKampen.lean +++ b/Mathlib/CategoryTheory/Limits/VanKampen.lean @@ -352,7 +352,7 @@ theorem IsUniversalColimit.map_reflective · intro j rw [← Category.assoc, Iso.comp_inv_eq] ext - all_goals simp only [PreservesPullback.iso_hom_fst, PreservesPullback.iso_hom_snd, + all_goals simp only [c'', PreservesPullback.iso_hom_fst, PreservesPullback.iso_hom_snd, pullback.lift_fst, pullback.lift_snd, Category.assoc, Functor.mapCocone_ι_app, ← Gl.map_comp] · rw [IsIso.comp_inv_eq, adj.counit_naturality] @@ -363,7 +363,8 @@ theorem IsUniversalColimit.map_reflective rw [Category.comp_id, Category.assoc] have : cf.hom ≫ (PreservesPullback.iso _ _ _).hom ≫ pullback.fst _ _ ≫ adj.counit.app _ = 𝟙 _ := by - simp only [IsIso.inv_hom_id, Iso.inv_hom_id_assoc, Category.assoc, pullback.lift_fst_assoc] + simp only [cf, IsIso.inv_hom_id, Iso.inv_hom_id_assoc, Category.assoc, + pullback.lift_fst_assoc] have : IsIso cf := by apply @Cocones.cocone_iso_of_hom_iso (i := ?_) rw [← IsIso.eq_comp_inv] at this @@ -373,12 +374,12 @@ theorem IsUniversalColimit.map_reflective · exact ⟨IsColimit.precomposeHomEquiv β c' <| (isColimitOfPreserves Gl Hc'').ofIsoColimit (asIso cf).symm⟩ · ext j - dsimp + dsimp [c''] simp only [Category.comp_id, Category.id_comp, Category.assoc, Functor.map_comp, pullback.lift_snd] · intro j apply IsPullback.of_right _ _ (IsPullback.of_hasPullback _ _) - · dsimp [α'] + · dsimp [α', c''] simp only [Category.comp_id, Category.id_comp, Category.assoc, Functor.map_comp, pullback.lift_fst] rw [← Category.comp_id (Gr.map f)] @@ -390,7 +391,7 @@ theorem IsUniversalColimit.map_reflective dsimp simp only [Category.comp_id, Adjunction.right_triangle_components, Category.id_comp, Category.assoc] - · dsimp + · dsimp [c''] simp only [Category.comp_id, Category.id_comp, Category.assoc, Functor.map_comp, pullback.lift_snd] @@ -506,7 +507,7 @@ theorem BinaryCofan.isVanKampen_iff (c : BinaryCofan X Y) : have : F' = pair X' Y' := by apply Functor.hext · rintro ⟨⟨⟩⟩ <;> rfl - · rintro ⟨⟨⟩⟩ ⟨j⟩ ⟨⟨rfl : _ = j⟩⟩ <;> simp + · rintro ⟨⟨⟩⟩ ⟨j⟩ ⟨⟨rfl : _ = j⟩⟩ <;> simp [X', Y'] clear_value X' Y' subst this change BinaryCofan X' Y' at c' diff --git a/Mathlib/CategoryTheory/Linear/Yoneda.lean b/Mathlib/CategoryTheory/Linear/Yoneda.lean index ee468da7d7708..ae48cbcbb39b7 100644 --- a/Mathlib/CategoryTheory/Linear/Yoneda.lean +++ b/Mathlib/CategoryTheory/Linear/Yoneda.lean @@ -28,9 +28,6 @@ namespace CategoryTheory variable (R : Type w) [Ring R] {C : Type u} [Category.{v} C] [Preadditive C] [Linear R C] variable (C) --- Porting note: inserted specific `ModuleCat.asHom` in the definition of `linearYoneda` --- and similarly in `linearCoyoneda`, otherwise many simp lemmas are not triggered automatically. --- Eventually, doing so allows more proofs to be automatic! /-- The Yoneda embedding for `R`-linear categories `C`, sending an object `X : C` to the `ModuleCat R`-valued presheaf on `C`, with value on `Y : Cᵒᵖ` given by `ModuleCat.of R (unop Y ⟶ X)`. -/ @@ -38,9 +35,9 @@ with value on `Y : Cᵒᵖ` given by `ModuleCat.of R (unop Y ⟶ X)`. -/ def linearYoneda : C ⥤ Cᵒᵖ ⥤ ModuleCat R where obj X := { obj := fun Y => ModuleCat.of R (unop Y ⟶ X) - map := fun f => ModuleCat.asHom (Linear.leftComp R _ f.unop) } + map := fun f => ModuleCat.ofHom (Linear.leftComp R _ f.unop) } map {X₁ X₂} f := - { app := fun Y => @ModuleCat.asHom R _ (Y.unop ⟶ X₁) (Y.unop ⟶ X₂) _ _ _ _ + { app := fun Y => @ModuleCat.ofHom R _ (Y.unop ⟶ X₁) (Y.unop ⟶ X₂) _ _ _ _ (Linear.rightComp R _ f) } /-- The Yoneda embedding for `R`-linear categories `C`, @@ -50,9 +47,9 @@ with value on `X : C` given by `ModuleCat.of R (unop Y ⟶ X)`. -/ def linearCoyoneda : Cᵒᵖ ⥤ C ⥤ ModuleCat R where obj Y := { obj := fun X => ModuleCat.of R (unop Y ⟶ X) - map := fun f => ModuleCat.asHom (Linear.rightComp R _ f) } + map := fun f => ModuleCat.ofHom (Linear.rightComp R _ f) } map {Y₁ Y₂} f := - { app := fun X => @ModuleCat.asHom R _ (unop Y₁ ⟶ X) (unop Y₂ ⟶ X) _ _ _ _ + { app := fun X => @ModuleCat.ofHom R _ (unop Y₁ ⟶ X) (unop Y₂ ⟶ X) _ _ _ _ (Linear.leftComp _ _ f.unop) } instance linearYoneda_obj_additive (X : C) : ((linearYoneda R C).obj X).Additive where diff --git a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean index ab6a1a44daa7d..a27c2821017c6 100644 --- a/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean +++ b/Mathlib/CategoryTheory/Localization/CalculusOfFractions.lean @@ -385,9 +385,9 @@ noncomputable def Hom.comp {X Y Z : C} (z₁ : Hom W X Y) (z₂ : Hom W Y Z) : H obtain ⟨Z, u, hu, fac₃⟩ := HasLeftCalculusOfFractions.ext _ _ _ a₁.hs eq simp only [assoc] at fac₃ refine ⟨Z, w₁.s ≫ u, u, ?_, ?_, ?_⟩ - · dsimp + · dsimp [p₁] simp only [assoc] - · dsimp + · dsimp [p₁] simp only [assoc, fac₃] · dsimp simp only [assoc] @@ -401,9 +401,9 @@ noncomputable def Hom.comp {X Y Z : C} (z₁ : Hom W X Y) (z₂ : Hom W Y Z) : H obtain ⟨Z, u, hu, fac₄⟩ := HasLeftCalculusOfFractions.ext _ _ _ a₁.hs eq simp only [assoc] at fac₄ refine ⟨Z, q.f ≫ u, q.s ≫ u, ?_, ?_, ?_⟩ - · simp only [assoc, reassoc_of% fac₃] + · simp only [p₁, p₂, assoc, reassoc_of% fac₃] · rw [assoc, assoc, assoc, assoc, fac₄, reassoc_of% hft] - · simp only [assoc, ← reassoc_of% fac₃] + · simp only [p₁, p₂, 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 @@ -411,11 +411,11 @@ noncomputable def Hom.comp {X Y Z : C} (z₁ : Hom W X Y) (z₂ : Hom W Y Z) : H obtain ⟨Z, u, hu, fac₄⟩ := HasLeftCalculusOfFractions.ext _ _ _ a₂.hs eq simp only [assoc] at fac₄ refine ⟨Z, u, w₂.s ≫ u, ?_, ?_, ?_⟩ - · dsimp + · dsimp [p₁, p₂] simp only [assoc] - · dsimp + · dsimp [p₁, p₂] simp only [assoc, fac₄] - · dsimp + · dsimp [p₁, p₂] simp only [assoc] exact W.comp_mem _ _ b.hs (W.comp_mem _ _ z₂.hs (W.comp_mem _ _ w₂.hs hu)) diff --git a/Mathlib/CategoryTheory/Monoidal/Bimon_.lean b/Mathlib/CategoryTheory/Monoidal/Bimon_.lean index 4b3678918fac2..69026eb1f7464 100644 --- a/Mathlib/CategoryTheory/Monoidal/Bimon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Bimon_.lean @@ -157,14 +157,20 @@ def trivial : Bimon_ C := Comon_.trivial (Mon_ C) /-- The bimonoid morphism from the trivial bimonoid to any bimonoid. -/ @[simps] -def trivial_to (A : Bimon_ C) : trivial C ⟶ A := +def trivialTo (A : Bimon_ C) : trivial C ⟶ A := { hom := (default : Mon_.trivial C ⟶ A.X), } +@[deprecated (since := "2024-12-07")] alias trivial_to := trivialTo +@[deprecated (since := "2024-12-07")] alias trivial_to_hom := trivialTo_hom + /-- The bimonoid morphism from any bimonoid to the trivial bimonoid. -/ @[simps!] -def to_trivial (A : Bimon_ C) : A ⟶ trivial C := +def toTrivial (A : Bimon_ C) : A ⟶ trivial C := (default : @Quiver.Hom (Comon_ (Mon_ C)) _ A (Comon_.trivial (Mon_ C))) +@[deprecated (since := "2024-12-07")] alias to_trivial := toTrivial +@[deprecated (since := "2024-12-07")] alias to_trivial_hom := toTrivial_hom + /-! # Additional lemmas -/ variable {C} diff --git a/Mathlib/CategoryTheory/Monoidal/Functor.lean b/Mathlib/CategoryTheory/Monoidal/Functor.lean index 72a7a69ef0039..83192bd9443b1 100644 --- a/Mathlib/CategoryTheory/Monoidal/Functor.lean +++ b/Mathlib/CategoryTheory/Monoidal/Functor.lean @@ -25,9 +25,9 @@ inverse isomorphisms. We show that the composition of (lax) monoidal functors gives a (lax) monoidal functor. -See `CategoryTheory.Monoidal.NaturalTransformation` for monoidal natural transformations. +See `Mathlib.CategoryTheory.Monoidal.NaturalTransformation` for monoidal natural transformations. -We show in `CategoryTheory.Monoidal.Mon_` that lax monoidal functors take monoid objects +We show in `Mathlib.CategoryTheory.Monoidal.Mon_` that lax monoidal functors take monoid objects to monoid objects. ## References @@ -972,7 +972,7 @@ instance [e.functor.Monoidal] : e.symm.inverse.Monoidal := inferInstanceAs (e.fu noncomputable def inverseMonoidal [e.functor.Monoidal] : e.inverse.Monoidal := by letI := e.toAdjunction.rightAdjointLaxMonoidal have : IsIso (LaxMonoidal.ε e.inverse) := by - simp only [Adjunction.rightAdjointLaxMonoidal_ε, Adjunction.homEquiv_unit] + simp only [this, Adjunction.rightAdjointLaxMonoidal_ε, Adjunction.homEquiv_unit] infer_instance have : ∀ (X Y : D), IsIso (LaxMonoidal.μ e.inverse X Y) := fun X Y ↦ by simp only [Adjunction.rightAdjointLaxMonoidal_μ, Adjunction.homEquiv_unit] diff --git a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean index 9341953c58518..94382ab42f817 100644 --- a/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean +++ b/Mathlib/CategoryTheory/Monoidal/Internal/Module.lean @@ -45,19 +45,19 @@ instance Ring_of_Mon_ (A : Mon_ (ModuleCat.{u} R)) : Ring A.X := one := A.one (1 : R) mul := fun x y => A.mul (x ⊗ₜ y) one_mul := fun x => by - convert LinearMap.congr_fun A.one_mul ((1 : R) ⊗ₜ x) + convert LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.one_mul) ((1 : R) ⊗ₜ x) rw [MonoidalCategory.leftUnitor_hom_apply, one_smul] mul_one := fun x => by - convert LinearMap.congr_fun A.mul_one (x ⊗ₜ (1 : R)) - erw [MonoidalCategory.leftUnitor_hom_apply, one_smul] + convert LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.mul_one) (x ⊗ₜ (1 : R)) + rw [MonoidalCategory.rightUnitor_hom_apply, one_smul] mul_assoc := fun x y z => by - convert LinearMap.congr_fun A.mul_assoc (x ⊗ₜ y ⊗ₜ z) + convert LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.mul_assoc) (x ⊗ₜ y ⊗ₜ z) left_distrib := fun x y z => by - convert A.mul.map_add (x ⊗ₜ y) (x ⊗ₜ z) + convert A.mul.hom.map_add (x ⊗ₜ y) (x ⊗ₜ z) rw [← TensorProduct.tmul_add] rfl right_distrib := fun x y z => by - convert A.mul.map_add (x ⊗ₜ z) (y ⊗ₜ z) + convert A.mul.hom.map_add (x ⊗ₜ z) (y ⊗ₜ z) rw [← TensorProduct.add_tmul] rfl zero_mul := fun x => show A.mul _ = 0 by @@ -66,18 +66,19 @@ instance Ring_of_Mon_ (A : Mon_ (ModuleCat.{u} R)) : Ring A.X := rw [TensorProduct.tmul_zero, map_zero] } instance Algebra_of_Mon_ (A : Mon_ (ModuleCat.{u} R)) : Algebra R A.X := - { A.one with - map_zero' := A.one.map_zero + { A.one.hom with + map_zero' := A.one.hom.map_zero map_one' := rfl map_mul' := fun x y => by - have h := LinearMap.congr_fun A.one_mul.symm (x ⊗ₜ A.one y) - rwa [MonoidalCategory.leftUnitor_hom_apply, ← A.one.map_smul] at h + have h := LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.one_mul.symm) (x ⊗ₜ A.one y) + rwa [MonoidalCategory.leftUnitor_hom_apply, ← A.one.hom.map_smul] at h commutes' := fun r a => by dsimp - have h₁ := LinearMap.congr_fun A.one_mul (r ⊗ₜ a) - have h₂ := LinearMap.congr_fun A.mul_one (a ⊗ₜ r) + have h₁ := LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.one_mul) (r ⊗ₜ a) + have h₂ := LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.mul_one) (a ⊗ₜ r) exact h₁.trans h₂.symm - smul_def' := fun r a => (LinearMap.congr_fun A.one_mul (r ⊗ₜ a)).symm } + smul_def' := fun r a => + (LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp A.one_mul) (r ⊗ₜ a)).symm } @[simp] theorem algebraMap (A : Mon_ (ModuleCat.{u} R)) (r : R) : algebraMap R A.X r = A.one r := @@ -89,33 +90,35 @@ theorem algebraMap (A : Mon_ (ModuleCat.{u} R)) (r : R) : algebraMap R A.X r = A def functor : Mon_ (ModuleCat.{u} R) ⥤ AlgebraCat R where obj A := AlgebraCat.of R A.X map {_ _} f := AlgebraCat.ofHom - { f.hom.toAddMonoidHom with + { f.hom.hom.toAddMonoidHom with toFun := f.hom - map_one' := LinearMap.congr_fun f.one_hom (1 : R) - map_mul' := fun x y => LinearMap.congr_fun f.mul_hom (x ⊗ₜ y) - commutes' := fun r => LinearMap.congr_fun f.one_hom r } + map_one' := LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp f.one_hom) (1 : R) + map_mul' := fun x y => LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp f.mul_hom) (x ⊗ₜ y) + commutes' := fun r => LinearMap.congr_fun (ModuleCat.hom_ext_iff.mp f.one_hom) r } /-- Converting a bundled algebra to a monoid object in `ModuleCat R`. -/ @[simps] def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where X := ModuleCat.of R A - one := Algebra.linearMap R A - mul := LinearMap.mul' R A + one := ofHom <| Algebra.linearMap R A + mul := ofHom <| LinearMap.mul' R A one_mul := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext <| LinearMap.ext_ring <| LinearMap.ext fun x => ?_ - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [compr₂_apply, compr₂_apply, CategoryTheory.comp_apply] + rw [compr₂_apply, compr₂_apply, hom_comp, LinearMap.comp_apply] -- Porting note: this `dsimp` does nothing -- dsimp [AlgebraCat.id_apply, TensorProduct.mk_apply, Algebra.linearMap_apply, - -- LinearMap.compr₂_apply, Function.comp_apply, RingHom.map_one, - -- ModuleCat.MonoidalCategory.hom_apply, AlgebraCat.coe_comp, - -- ModuleCat.MonoidalCategory.leftUnitor_hom_apply] + -- LinearMap.compr₂_apply, Function.comp_apply, RingHom.map_one, + -- ModuleCat.MonoidalCategory.tensorHom_tmul, AlgebraCat.hom_comp, + -- ModuleCat.MonoidalCategory.leftUnitor_hom_apply] -- Porting note: because `dsimp` is not effective, `rw` needs to be changed to `erw` + dsimp erw [LinearMap.mul'_apply, MonoidalCategory.leftUnitor_hom_apply, ← Algebra.smul_def] - erw [id_apply] + dsimp mul_one := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext <| LinearMap.ext fun x => LinearMap.ext_ring ?_ -- Porting note: this `dsimp` does nothing @@ -124,23 +127,22 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where -- AlgebraCat.coe_comp] -- Porting note: because `dsimp` is not effective, `rw` needs to be changed to `erw` erw [compr₂_apply, compr₂_apply] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [CategoryTheory.comp_apply] + rw [ModuleCat.hom_comp, LinearMap.comp_apply] erw [LinearMap.mul'_apply, ModuleCat.MonoidalCategory.rightUnitor_hom_apply, ← Algebra.commutes, ← Algebra.smul_def] - erw [id_apply] + dsimp mul_assoc := by + ext : 1 set_option tactic.skipAssignedInstances false in -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext <| TensorProduct.ext <| LinearMap.ext fun x => LinearMap.ext fun y => LinearMap.ext fun z => ?_ dsimp only [compr₂_apply, TensorProduct.mk_apply] rw [compr₂_apply, compr₂_apply] - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [CategoryTheory.comp_apply, - CategoryTheory.comp_apply, CategoryTheory.comp_apply] + rw [hom_comp, LinearMap.comp_apply, hom_comp, LinearMap.comp_apply, hom_comp, + LinearMap.comp_apply] erw [LinearMap.mul'_apply, LinearMap.mul'_apply] - erw [id_apply] + dsimp only [id_coe, id_eq] erw [TensorProduct.mk_apply, TensorProduct.mk_apply, mul'_apply, LinearMap.id_apply, mul'_apply] simp only [LinearMap.mul'_apply, mul_assoc] @@ -150,9 +152,9 @@ def inverseObj (A : AlgebraCat.{u} R) : Mon_ (ModuleCat.{u} R) where def inverse : AlgebraCat.{u} R ⥤ Mon_ (ModuleCat.{u} R) where obj := inverseObj map f := - { hom := f.hom.toLinearMap - one_hom := LinearMap.ext f.hom.commutes - mul_hom := TensorProduct.ext <| LinearMap.ext₂ <| map_mul f.hom } + { hom := ofHom <| f.hom.toLinearMap + one_hom := hom_ext <| LinearMap.ext f.hom.commutes + mul_hom := hom_ext <| TensorProduct.ext <| LinearMap.ext₂ <| map_mul f.hom } end MonModuleEquivalenceAlgebra @@ -169,21 +171,23 @@ def monModuleEquivalenceAlgebra : Mon_ (ModuleCat.{u} R) ≌ AlgebraCat R where NatIso.ofComponents (fun A => { hom := - { hom := + { hom := ofHom { toFun := _root_.id map_add' := fun _ _ => rfl map_smul' := fun _ _ => rfl } mul_hom := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext ?_ dsimp at * rfl } inv := - { hom := + { hom := ofHom { toFun := _root_.id map_add' := fun _ _ => rfl map_smul' := fun _ _ => rfl } mul_hom := by + ext : 1 -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11041): `ext` did not pick up `TensorProduct.ext` refine TensorProduct.ext ?_ dsimp at * @@ -214,11 +218,11 @@ def monModuleEquivalenceAlgebraForget : Mon_.forget (ModuleCat.{u} R) := NatIso.ofComponents (fun A => - { hom := + { hom := ofHom { toFun := _root_.id map_add' := fun _ _ => rfl map_smul' := fun _ _ => rfl } - inv := + inv := ofHom { toFun := _root_.id map_add' := fun _ _ => rfl map_smul' := fun _ _ => rfl } }) diff --git a/Mathlib/CategoryTheory/Monoidal/Mod_.lean b/Mathlib/CategoryTheory/Monoidal/Mod_.lean index ec6327ca22917..da996f019d255 100644 --- a/Mathlib/CategoryTheory/Monoidal/Mod_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Mod_.lean @@ -88,6 +88,14 @@ def forget : Mod_ A ⥤ C where open CategoryTheory.MonoidalCategory +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6053 +we needed to increase the `maxHeartbeats` limit. + +This may indicate a configuration problem in Aesop. +-/ +set_option maxHeartbeats 400000 in /-- A morphism of monoid objects induces a "restriction" or "comap" functor between the categories of module objects. -/ diff --git a/Mathlib/CategoryTheory/Monoidal/Mon_.lean b/Mathlib/CategoryTheory/Monoidal/Mon_.lean index 90677e4b70360..cff040d32fd90 100644 --- a/Mathlib/CategoryTheory/Monoidal/Mon_.lean +++ b/Mathlib/CategoryTheory/Monoidal/Mon_.lean @@ -246,6 +246,14 @@ namespace CategoryTheory.Functor variable {C} {D : Type u₂} [Category.{v₂} D] [MonoidalCategory.{v₂} D] +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6053 +we needed to increase the `maxHeartbeats` limit. + +This may indicate a configuration problem in Aesop. +-/ +set_option maxHeartbeats 400000 in -- TODO: mapMod F A : Mod A ⥤ Mod (F.mapMon A) /-- A lax monoidal functor takes monoid objects to monoid objects. @@ -511,10 +519,10 @@ instance monMonoidalStruct : MonoidalCategoryStruct (Mon_ C) := tensorObj _ _ ⟶ tensorObj _ _ := { hom := f.hom ⊗ g.hom one_hom := by - dsimp + dsimp [tensorObj] slice_lhs 2 3 => rw [← tensor_comp, Hom.one_hom f, Hom.one_hom g] mul_hom := by - dsimp + dsimp [tensorObj] slice_rhs 1 2 => rw [tensorμ_natural] slice_lhs 2 3 => rw [← tensor_comp, Hom.mul_hom f, Hom.mul_hom g, tensor_comp] simp only [Category.assoc] } diff --git a/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean b/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean index 44711f734e411..16ed860f8bcb4 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/IsInvertedBy.lean @@ -126,10 +126,7 @@ lemma IsInvertedBy.isoClosure_iff (W : MorphismProperty C) (F : C ⥤ D) : · intro h X Y f hf exact h _ (W.le_isoClosure _ hf) · intro h X Y f ⟨X', Y', f', hf', ⟨e⟩⟩ - have : f = e.inv.left ≫ f' ≫ e.hom.right := by - erw [← e.hom.w, ← Arrow.comp_left_assoc, e.inv_hom_id, Category.id_comp] - rfl - simp only [this, F.map_comp] + simp only [Arrow.iso_w' e, F.map_comp] have := h _ hf' infer_instance diff --git a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean index 053633f2b164d..b1bfa27cc46f1 100644 --- a/Mathlib/CategoryTheory/MorphismProperty/Limits.lean +++ b/Mathlib/CategoryTheory/MorphismProperty/Limits.lean @@ -252,7 +252,7 @@ lemma IsStableUnderProductsOfShape.mk (J : Type*) (IsLimit.conePointUniqueUpToIso hc₂ (limit.isLimit X₂) ≪≫ (Pi.isoLimit _).symm) ?_ apply limit.hom_ext rintro ⟨j⟩ - simp + simp [φ] /-- The condition that a property of morphisms is stable by finite products. -/ class IsStableUnderFiniteProducts : Prop where diff --git a/Mathlib/CategoryTheory/MorphismProperty/Retract.lean b/Mathlib/CategoryTheory/MorphismProperty/Retract.lean new file mode 100644 index 0000000000000..af653b25df92e --- /dev/null +++ b/Mathlib/CategoryTheory/MorphismProperty/Retract.lean @@ -0,0 +1,52 @@ +/- +Copyright (c) 2024 Jack McKoen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jack McKoen +-/ +import Mathlib.CategoryTheory.Retract +import Mathlib.CategoryTheory.MorphismProperty.Basic + +/-! +# Stability under retracts + +Given `P : MorphismProperty C`, we introduce a typeclass `P.IsStableUnderRetracts` which +is the property that `P` is stable under retracts. + +-/ + +universe v u + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] + +namespace MorphismProperty + +/-- A class of morphisms is stable under retracts if a retract of such a morphism still +lies in the class. -/ +class IsStableUnderRetracts (P : MorphismProperty C) : Prop where + of_retract {X Y Z W : C} {f : X ⟶ Y} {g : Z ⟶ W} (h : RetractArrow f g) (hg : P g) : P f + +lemma of_retract {P : MorphismProperty C} [P.IsStableUnderRetracts] + {X Y Z W : C} {f : X ⟶ Y} {g : Z ⟶ W} (h : RetractArrow f g) (hg : P g) : P f := + IsStableUnderRetracts.of_retract h hg + +instance IsStableUnderRetracts.monomorphisms : (monomorphisms C).IsStableUnderRetracts where + of_retract {_ _ _ _ f g} h (hg : Mono g) := ⟨fun α β w ↦ by + rw [← cancel_mono h.i.left, ← cancel_mono g, Category.assoc, Category.assoc, + h.i_w, reassoc_of% w]⟩ + +instance IsStableUnderRetracts.epimorphisms : (epimorphisms C).IsStableUnderRetracts where + of_retract {_ _ _ _ f g} h (hg : Epi g) := ⟨fun α β w ↦ by + rw [← cancel_epi h.r.right, ← cancel_epi g, ← Category.assoc, ← Category.assoc, ← h.r_w, + Category.assoc, Category.assoc, w]⟩ + +instance IsStableUnderRetracts.isomorphisms : (isomorphisms C).IsStableUnderRetracts where + of_retract {X Y Z W f g} h (_ : IsIso _) := by + refine ⟨h.i.right ≫ inv g ≫ h.r.left, ?_, ?_⟩ + · rw [← h.i_w_assoc, IsIso.hom_inv_id_assoc, h.retract_left] + · rw [Category.assoc, Category.assoc, h.r_w, IsIso.inv_hom_id_assoc, h.retract_right] + +end MorphismProperty + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean b/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean index 812bfc902cea1..beedbdb8d0a67 100644 --- a/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean +++ b/Mathlib/CategoryTheory/Preadditive/Yoneda/Basic.lean @@ -39,7 +39,7 @@ object `X` to the `End Y`-module of morphisms `X ⟶ Y`. @[simps] def preadditiveYonedaObj (Y : C) : Cᵒᵖ ⥤ ModuleCat.{v} (End Y) where obj X := ModuleCat.of _ (X.unop ⟶ Y) - map f := ModuleCat.asHom + map f := ModuleCat.ofHom { toFun := fun g => f.unop ≫ g map_add' := fun _ _ => comp_add _ _ _ _ _ _ map_smul' := fun _ _ => Eq.symm <| Category.assoc _ _ _ } @@ -66,7 +66,7 @@ object `Y` to the `End X`-module of morphisms `X ⟶ Y`. @[simps] def preadditiveCoyonedaObj (X : Cᵒᵖ) : C ⥤ ModuleCat.{v} (End X) where obj Y := ModuleCat.of _ (unop X ⟶ Y) - map f := ModuleCat.asHom + map f := ModuleCat.ofHom { toFun := fun g => g ≫ f map_add' := fun _ _ => add_comp _ _ _ _ _ _ map_smul' := fun _ _ => Category.assoc _ _ _ } diff --git a/Mathlib/CategoryTheory/Quotient/Linear.lean b/Mathlib/CategoryTheory/Quotient/Linear.lean index bdb9c5b50e4a7..492d4c887729f 100644 --- a/Mathlib/CategoryTheory/Quotient/Linear.lean +++ b/Mathlib/CategoryTheory/Quotient/Linear.lean @@ -49,30 +49,30 @@ lemma smul_eq (hr : ∀ (a : R) ⦃X Y : C⦄ (f₁ f₂ : X ⟶ Y) (_ : r f₁ def module' (hr : ∀ (a : R) ⦃X Y : C⦄ (f₁ f₂ : X ⟶ Y) (_ : r f₁ f₂), r (a • f₁) (a • f₂)) [Preadditive (Quotient r)] [(functor r).Additive] (X Y : C) : Module R ((functor r).obj X ⟶ (functor r).obj Y) := - letI := smul r hr ((functor r).obj X) ((functor r).obj Y) + letI smul := smul r hr ((functor r).obj X) ((functor r).obj Y) { smul_zero := fun a => by dsimp rw [← (functor r).map_zero X Y, smul_eq, smul_zero] zero_smul := fun f => by obtain ⟨f, rfl⟩ := (functor r).map_surjective f - dsimp + dsimp [smul] rw [zero_smul, Functor.map_zero] one_smul := fun f => by obtain ⟨f, rfl⟩ := (functor r).map_surjective f - dsimp + dsimp [smul] rw [one_smul] mul_smul := fun a b f => by obtain ⟨f, rfl⟩ := (functor r).map_surjective f - dsimp + dsimp [smul] rw [mul_smul] smul_add := fun a f g => by obtain ⟨f, rfl⟩ := (functor r).map_surjective f obtain ⟨g, rfl⟩ := (functor r).map_surjective g - dsimp + dsimp [smul] rw [← (functor r).map_add, smul_eq, ← (functor r).map_add, smul_add] add_smul := fun a b f => by obtain ⟨f, rfl⟩ := (functor r).map_surjective f - dsimp + dsimp [smul] rw [add_smul, Functor.map_add] } /-- Auxiliary definition for `Quotient.linear`. -/ diff --git a/Mathlib/CategoryTheory/Retract.lean b/Mathlib/CategoryTheory/Retract.lean new file mode 100644 index 0000000000000..952554b768d5a --- /dev/null +++ b/Mathlib/CategoryTheory/Retract.lean @@ -0,0 +1,106 @@ +/- +Copyright (c) 2024 Jack McKoen. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jack McKoen +-/ +import Mathlib.CategoryTheory.Comma.Arrow +import Mathlib.CategoryTheory.EpiMono + +/-! +# Retracts + +Defines retracts of objects and morphisms. + +-/ + +universe v v' u u' + +namespace CategoryTheory + +variable {C : Type u} [Category.{v} C] {D : Type u'} [Category.{v'} D] + +/-- An object `X` is a retract of `Y` if there are morphisms `i : X ⟶ Y` and `r : Y ⟶ X` such +that `i ≫ r = 𝟙 X`. -/ +structure Retract (X Y : C) where + /-- the split monomorphism -/ + i : X ⟶ Y + /-- the split epimorphism -/ + r : Y ⟶ X + retract : i ≫ r = 𝟙 X := by aesop_cat + +namespace Retract + +attribute [reassoc (attr := simp)] retract + +variable {X Y : C} (h : Retract X Y) + +/-- If `X` is a retract of `Y`, then `F.obj X` is a retract of `F.obj Y`. -/ +@[simps] +def map (F : C ⥤ D) : Retract (F.obj X) (F.obj Y) where + i := F.map h.i + r := F.map h.r + retract := by rw [← F.map_comp h.i h.r, h.retract, F.map_id] + +/-- a retract determines a split epimorphism. -/ +@[simps] def splitEpi : SplitEpi h.r where + section_ := h.i + +/-- a retract determines a split monomorphism. -/ +@[simps] def splitMono : SplitMono h.i where + retraction := h.r + +instance : IsSplitEpi h.r := ⟨⟨h.splitEpi⟩⟩ + +instance : IsSplitMono h.i := ⟨⟨h.splitMono⟩⟩ + +end Retract + +/-- +``` + X -------> Z -------> X + | | | + f g f + | | | + v v v + Y -------> W -------> Y + +``` +A morphism `f : X ⟶ Y` is a retract of `g : Z ⟶ W` if there are morphisms `i : f ⟶ g` +and `r : g ⟶ f` in the arrow category such that `i ≫ r = 𝟙 f`. -/ +abbrev RetractArrow {X Y Z W : C} (f : X ⟶ Y) (g : Z ⟶ W) := Retract (Arrow.mk f) (Arrow.mk g) + +namespace RetractArrow + +variable {X Y Z W : C} {f : X ⟶ Y} {g : Z ⟶ W} (h : RetractArrow f g) + +@[reassoc] +lemma i_w : h.i.left ≫ g = f ≫ h.i.right := h.i.w + +@[reassoc] +lemma r_w : h.r.left ≫ f = g ≫ h.r.right := h.r.w + +/-- The top of a retract diagram of morphisms determines a retract of objects. -/ +@[simps!] +def left : Retract X Z := h.map Arrow.leftFunc + +/-- The bottom of a retract diagram of morphisms determines a retract of objects. -/ +@[simps!] +def right : Retract Y W := h.map Arrow.rightFunc + +@[reassoc (attr := simp)] +lemma retract_left : h.i.left ≫ h.r.left = 𝟙 X := h.left.retract + +@[reassoc (attr := simp)] +lemma retract_right : h.i.right ≫ h.r.right = 𝟙 Y := h.right.retract + +instance : IsSplitEpi h.r.left := ⟨⟨h.left.splitEpi⟩⟩ + +instance : IsSplitEpi h.r.right := ⟨⟨h.right.splitEpi⟩⟩ + +instance : IsSplitMono h.i.left := ⟨⟨h.left.splitMono⟩⟩ + +instance : IsSplitMono h.i.right := ⟨⟨h.right.splitMono⟩⟩ + +end RetractArrow + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Sites/Adjunction.lean b/Mathlib/CategoryTheory/Sites/Adjunction.lean index 8b4192d40635c..eb19bd7cd03c8 100644 --- a/Mathlib/CategoryTheory/Sites/Adjunction.lean +++ b/Mathlib/CategoryTheory/Sites/Adjunction.lean @@ -100,8 +100,8 @@ variable [HasWeakSheafify J D] [ConcreteCategory D] [HasSheafCompose J (forget D @[deprecated (since := "2024-11-26")] alias composeAndSheafifyFromTypes := composeAndSheafify -/-- The adjunction `composeAndSheafify J G ⊣ sheafForget J`. (Use `Sheaf.adjunction`.)-/ -@[deprecated (since := "2024-11-26")] abbrev adjunctionToTypes +/-- The adjunction `composeAndSheafify J G ⊣ sheafForget J`. -/ +@[deprecated Sheaf.adjunction (since := "2024-11-26")] abbrev adjunctionToTypes {G : Type max v₁ u₁ ⥤ D} (adj : G ⊣ forget D) : composeAndSheafify J G ⊣ sheafForget J := adjunction _ adj diff --git a/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean b/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean index f0f439fb8e122..de848d9cbf352 100644 --- a/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean +++ b/Mathlib/CategoryTheory/Sites/Coherent/Comparison.lean @@ -45,11 +45,11 @@ instance [FinitaryPreExtensive C] [Preregular C] : Precoherent C where let π' := fun a ↦ pullback.fst g' (Sigma.ι X₁ a) have _ := FinitaryPreExtensive.sigma_desc_iso (fun a ↦ Sigma.ι X₁ a) g' inferInstance refine ⟨X₂, π₂, ?_, ?_⟩ - · have : (Sigma.desc π' ≫ g) = Sigma.desc π₂ := by ext; simp + · have : (Sigma.desc π' ≫ g) = Sigma.desc π₂ := by ext; simp [π₂, π'] rw [← effectiveEpi_desc_iff_effectiveEpiFamily, ← this] infer_instance · refine ⟨id, fun b ↦ pullback.snd _ _, fun b ↦ ?_⟩ - simp only [π₂, id_eq, Category.assoc, ← hg] + simp only [X₂, π₂, id_eq, Category.assoc, ← hg] rw [← Category.assoc, pullback.condition] simp diff --git a/Mathlib/CategoryTheory/Sites/CoverLifting.lean b/Mathlib/CategoryTheory/Sites/CoverLifting.lean index ff75491a36dbb..631707e2b37e5 100644 --- a/Mathlib/CategoryTheory/Sites/CoverLifting.lean +++ b/Mathlib/CategoryTheory/Sites/CoverLifting.lean @@ -145,7 +145,7 @@ lemma liftAux_map {Y : C} (f : G.obj Y ⟶ X) {W : C} (g : W ⟶ Y) (i : S.Arrow { g₁ := 𝟙 _ g₂ := h w := by simpa using w.symm } - simpa using s.condition r ) + simpa [r] using s.condition r ) lemma liftAux_map' {Y Y' : C} (f : G.obj Y ⟶ X) (f' : G.obj Y' ⟶ X) {W : C} (a : W ⟶ Y) (b : W ⟶ Y') (w : G.map a ≫ f = G.map b ≫ f') : diff --git a/Mathlib/CategoryTheory/Sites/CoverPreserving.lean b/Mathlib/CategoryTheory/Sites/CoverPreserving.lean index 67fded0c9b4c2..2e0f39951144f 100644 --- a/Mathlib/CategoryTheory/Sites/CoverPreserving.lean +++ b/Mathlib/CategoryTheory/Sites/CoverPreserving.lean @@ -132,7 +132,7 @@ theorem compatiblePreservingOfFlat {C : Type u₁} [Category.{v₁} C] {D : Type simp conv_lhs => rw [eq₁] conv_rhs => rw [eq₂] - simp only [op_comp, Functor.map_comp, types_comp_apply, eqToHom_op, eqToHom_map] + simp only [c, op_comp, Functor.map_comp, types_comp_apply, eqToHom_op, eqToHom_map] apply congr_arg -- Porting note: was `congr 1` which for some reason doesn't do anything here -- despite goal being of the form f a = f b, with f=`ℱ.val.map (Quiver.Hom.op c'.pt.hom)` /- diff --git a/Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean b/Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean index 7cc5b9aefa271..487e2c24802c2 100644 --- a/Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean +++ b/Mathlib/CategoryTheory/Sites/DenseSubsite/SheafEquiv.lean @@ -82,8 +82,9 @@ lemma isIso_ranCounit_app_of_isDenseSubsite (Y : Sheaf J A) (U X) : ⟨_, I.f ≫ i, ⟨l _ _ _ _ _ I.hf, by simp [hl]⟩⟩ refine Eq.trans ?_ (Y.2.amalgamate_map _ _ _ I').symm apply (Y.2 X _ (IsDenseSubsite.equalizer_mem J K G (l _ _ _ _ _ I.hf) - (l _ _ _ _ _ I'.hf) (by simp [hl]))).isSeparatedFor.ext fun V iUV (hiUV : _ = _) ↦ ?_ - simp [← Functor.map_comp, ← op_comp, hiUV] + (l _ _ _ _ _ I'.hf) (by simp [I', hl]))).isSeparatedFor.ext + fun V iUV (hiUV : _ = _) ↦ ?_ + simp [I', ← Functor.map_comp, ← op_comp, hiUV] refine ⟨(isPointwiseRightKanExtensionRanCounit G.op Y.1 (.op (G.obj U))).lift c, ?_⟩ · have := (isPointwiseRightKanExtensionRanCounit G.op Y.1 (.op (G.obj U))).fac c (.mk (𝟙 _)) simp only [id_obj, comp_obj, StructuredArrow.proj_obj, StructuredArrow.mk_right, diff --git a/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean b/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean index f0f3a969c4866..66852416acf33 100644 --- a/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean +++ b/Mathlib/CategoryTheory/Sites/EffectiveEpimorphic.lean @@ -68,9 +68,9 @@ def isColimitOfEffectiveEpiStruct {X Y : C} (f : Y ⟶ X) (Hf : EffectiveEpiStru let Y' : D := ⟨Over.mk f, 𝟙 _, by simp⟩ let Z' : D := ⟨Over.mk (g₁ ≫ f), g₁, rfl⟩ let g₁' : Z' ⟶ Y' := Over.homMk g₁ - let g₂' : Z' ⟶ Y' := Over.homMk g₂ (by simp [h]) + let g₂' : Z' ⟶ Y' := Over.homMk g₂ (by simp [Y', Z', h]) change F.map g₁' ≫ _ = F.map g₂' ≫ _ - simp only [S.w] + simp only [Y', F, S.w] fac := by rintro S ⟨T,g,hT⟩ dsimp @@ -113,7 +113,7 @@ def effectiveEpiStructOfIsColimit {X Y : C} (f : Y ⟶ X) intro W e h dsimp have := Hf.fac (aux e h) ⟨Over.mk f, 𝟙 _, by simp⟩ - dsimp at this; rw [this]; clear this + dsimp [aux] at this; rw [this]; clear this nth_rewrite 2 [← Category.id_comp e] apply h generalize_proofs hh @@ -181,7 +181,7 @@ def isColimitOfEffectiveEpiFamilyStruct {B : C} {α : Type*} let i₁ : Z' ⟶ A₁ := Over.homMk g₁ let i₂ : Z' ⟶ A₂ := Over.homMk g₂ change F.map i₁ ≫ _ = F.map i₂ ≫ _ - simp only [S.w] + simp only [F, A₁, A₂, S.w] fac := by intro S ⟨T, a, (g : T.left ⟶ X a), hT⟩ dsimp @@ -226,7 +226,7 @@ def effectiveEpiFamilyStructOfIsColimit {B : C} {α : Type*} intro W e h a dsimp have := H.fac (aux e h) ⟨Over.mk (π a), a, 𝟙 _, by simp⟩ - dsimp at this; rw [this]; clear this + dsimp [aux] at this; rw [this]; clear this conv_rhs => rw [← Category.id_comp (e a)] apply h generalize_proofs h1 h2 diff --git a/Mathlib/CategoryTheory/Sites/Over.lean b/Mathlib/CategoryTheory/Sites/Over.lean index f012575ed625c..0714d53204dde 100644 --- a/Mathlib/CategoryTheory/Sites/Over.lean +++ b/Mathlib/CategoryTheory/Sites/Over.lean @@ -66,6 +66,13 @@ lemma overEquiv_symm_top {X : C} (Y : Over X) : (overEquiv Y).symm ⊤ = ⊤ := (overEquiv Y).injective (by simp) +lemma overEquiv_le_overEquiv_iff {X : C} {Y : Over X} (R₁ R₂ : Sieve Y) : + R₁.overEquiv Y ≤ R₂.overEquiv Y ↔ R₁ ≤ R₂ := by + refine ⟨fun h ↦ ?_, fun h ↦ Sieve.functorPushforward_monotone _ _ h⟩ + replace h : (overEquiv Y).symm (R₁.overEquiv Y) ≤ (overEquiv Y).symm (R₂.overEquiv Y) := + Sieve.functorPullback_monotone _ _ h + simpa using h + lemma overEquiv_pullback {X : C} {Y₁ Y₂ : Over X} (f : Y₁ ⟶ Y₂) (S : Sieve Y₂) : overEquiv _ (S.pullback f) = (overEquiv _ S).pullback f.left := by ext Z g @@ -77,7 +84,7 @@ lemma overEquiv_pullback {X : C} {Y₁ Y₂ : Over X} (f : Y₁ ⟶ Y₂) (S : S let T := Over.mk (b ≫ W.hom) let c : T ⟶ Y₁ := Over.homMk g (by dsimp [T]; rw [← Over.w a, ← reassoc_of% w, Over.w f]) let d : T ⟶ W := Over.homMk b - refine ⟨T, c, 𝟙 Z, ?_, by simp [c]⟩ + refine ⟨T, c, 𝟙 Z, ?_, by simp [T, c]⟩ rw [show c ≫ f = d ≫ a by ext; exact w] exact S.downward_closed h _ diff --git a/Mathlib/CategoryTheory/Sites/Sieves.lean b/Mathlib/CategoryTheory/Sites/Sieves.lean index 66591c5a8f117..38b3981948c40 100644 --- a/Mathlib/CategoryTheory/Sites/Sieves.lean +++ b/Mathlib/CategoryTheory/Sites/Sieves.lean @@ -756,6 +756,23 @@ lemma pullback_functorPushforward_equivalence_eq {X : C} (S : Sieve X) : Sieve.pullback (e.unit.app X) (Sieve.functorPushforward e.inverse (Sieve.functorPushforward e.functor S)) = S := by ext; simp +lemma mem_functorPushforward_iff_of_full [F.Full] {X Y : C} (R : Sieve X) (f : F.obj Y ⟶ F.obj X) : + (R.arrows.functorPushforward F) f ↔ ∃ (g : Y ⟶ X), F.map g = f ∧ R g := by + refine ⟨fun ⟨Z, g, h, hg, hcomp⟩ ↦ ?_, fun ⟨g, hcomp, hg⟩ ↦ ?_⟩ + · obtain ⟨h', hh'⟩ := F.map_surjective h + use h' ≫ g + simp only [Functor.map_comp, hh', hcomp, true_and] + apply R.downward_closed hg + · use Y, g, 𝟙 _, hg + simp [hcomp] + +lemma mem_functorPushforward_iff_of_full_of_faithful [F.Full] [F.Faithful] + {X Y : C} (R : Sieve X) (f : Y ⟶ X) : + (R.arrows.functorPushforward F) (F.map f) ↔ R f := by + rw [Sieve.mem_functorPushforward_iff_of_full] + refine ⟨fun ⟨g, hcomp, hg⟩ ↦ ?_, fun hf ↦ ⟨f, rfl, hf⟩⟩ + rwa [← F.map_injective hcomp] + end Functor /-- A sieve induces a presheaf. -/ diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean new file mode 100644 index 0000000000000..166469022df52 --- /dev/null +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/ExtendToSucc.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ + +import Mathlib.CategoryTheory.SmallObject.Iteration.Basic + +/-! +# Extension of a functor from `Set.Iic j` to `Set.Iic (Order.succ j)` + +Given a linearly ordered type `J` with `SuccOrder J`, `j : J` that is not maximal, +we define the extension of a functor `F : Set.Iic j ⥤ C` as a +functor `Set.Iic (Order.succ j) ⥤ C` when an object `X : C` and a morphism +`τ : F.obj ⟨j, _⟩ ⟶ X` is given. + +-/ + +universe u + +namespace CategoryTheory + +open Category + +namespace Functor + +variable {C : Type*} [Category C] + {J : Type u} [LinearOrder J] [SuccOrder J] {j : J} (hj : ¬IsMax j) + (F : Set.Iic j ⥤ C) {X : C} (τ : F.obj ⟨j, by simp⟩ ⟶ X) + +namespace extendToSucc + +variable (X) + +/-- `extendToSucc`, on objects: it coincides with `F.obj` for `i ≤ j`, and +it sends `Order.succ j` to the given object `X`. -/ +def obj (i : Set.Iic (Order.succ j)) : C := + if hij : i.1 ≤ j then F.obj ⟨i.1, hij⟩ else X + +/-- The isomorphism `obj F X ⟨i, _⟩ ≅ F.obj i` when `i : Set.Iic j`. -/ +def objIso (i : Set.Iic j) : + obj F X ⟨i, i.2.trans (Order.le_succ j)⟩ ≅ F.obj i := eqToIso (dif_pos i.2) + +/-- The isomorphism `obj F X ⟨Order.succ j, _⟩ ≅ X`. -/ +def objSuccIso : + obj F X ⟨Order.succ j, by simp⟩ ≅ X := + eqToIso (dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj)) + +variable {X} + +/-- `extendToSucc`, on morphisms. -/ +def map (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ Order.succ j) : + obj F X ⟨i₁, hi.trans hi₂⟩ ⟶ obj F X ⟨i₂, hi₂⟩ := + if h₁ : i₂ ≤ j then + (objIso F X ⟨i₁, hi.trans h₁⟩).hom ≫ F.map (homOfLE hi) ≫ (objIso F X ⟨i₂, h₁⟩).inv + else + if h₂ : i₁ ≤ j then + (objIso F X ⟨i₁, h₂⟩).hom ≫ F.map (homOfLE h₂) ≫ τ ≫ + (objSuccIso hj F X).inv ≫ eqToHom (by + congr + exact le_antisymm (Order.succ_le_of_lt (not_le.1 h₁)) hi₂) + else + eqToHom (by + congr + rw [le_antisymm hi₂ (Order.succ_le_of_lt (not_le.1 h₁)), + le_antisymm (hi.trans hi₂) (Order.succ_le_of_lt (not_le.1 h₂))]) + +lemma map_eq (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : + map hj F τ i₁ i₂ hi (hi₂.trans (Order.le_succ j)) = + (objIso F X ⟨i₁, hi.trans hi₂⟩).hom ≫ F.map (homOfLE hi) ≫ + (objIso F X ⟨i₂, hi₂⟩).inv := + dif_pos hi₂ + +lemma map_self_succ : + map hj F τ j (Order.succ j) (Order.le_succ j) (by rfl) = + (objIso F X ⟨j, by simp⟩).hom ≫ τ ≫ (objSuccIso hj F X).inv := by + dsimp [map] + rw [dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj), + dif_pos (by rfl), map_id, comp_id, id_comp] + +@[simp] +lemma map_id (i : J) (hi : i ≤ Order.succ j) : + map hj F τ i i (by rfl) hi = 𝟙 _ := by + dsimp [map] + by_cases h₁ : i ≤ j + · rw [dif_pos h₁, CategoryTheory.Functor.map_id, id_comp, Iso.hom_inv_id] + · obtain rfl : i = Order.succ j := le_antisymm hi (Order.succ_le_of_lt (not_le.1 h₁)) + rw [dif_neg (by simpa only [Order.succ_le_iff_isMax] using hj), + dif_neg h₁] + +lemma map_comp (i₁ i₂ i₃ : J) (h₁₂ : i₁ ≤ i₂) (h₂₃ : i₂ ≤ i₃) (h : i₃ ≤ Order.succ j) : + map hj F τ i₁ i₃ (h₁₂.trans h₂₃) h = + map hj F τ i₁ i₂ h₁₂ (h₂₃.trans h) ≫ map hj F τ i₂ i₃ h₂₃ h := by + by_cases h₁ : i₃ ≤ j + · rw [map_eq hj F τ i₁ i₂ _ (h₂₃.trans h₁), map_eq hj F τ i₂ i₃ _ h₁, + map_eq hj F τ i₁ i₃ _ h₁, assoc, assoc, Iso.inv_hom_id_assoc, ← map_comp_assoc, + homOfLE_comp] + · obtain rfl : i₃ = Order.succ j := le_antisymm h (Order.succ_le_of_lt (not_le.1 h₁)) + obtain h₂ | rfl := h₂₃.lt_or_eq + · rw [Order.lt_succ_iff_of_not_isMax hj] at h₂ + rw [map_eq hj F τ i₁ i₂ _ h₂] + dsimp [map] + rw [dif_neg h₁, dif_pos (h₁₂.trans h₂), dif_neg h₁, dif_pos h₂, + assoc, assoc, Iso.inv_hom_id_assoc,comp_id, ← map_comp_assoc, homOfLE_comp] + · rw [map_id, comp_id] + +end extendToSucc + +open extendToSucc in +include hj in +/-- The extension to `Set.Iic (Order.succ j) ⥤ C` of a functor `F : Set.Iic j ⥤ C`, +when we specify a morphism `F.obj ⟨j, _⟩ ⟶ X`. -/ +def extendToSucc : Set.Iic (Order.succ j) ⥤ C where + obj := obj F X + map {i₁ i₂} f := map hj F τ i₁ i₂ (leOfHom f) i₂.2 + map_id _ := extendToSucc.map_id _ F τ _ _ + map_comp {i₁ i₂ i₃} f g := extendToSucc.map_comp hj F τ i₁ i₂ i₃ (leOfHom f) (leOfHom g) i₃.2 + +/-- The isomorphism `(extendToSucc hj F τ).obj ⟨i, _⟩ ≅ F.obj i` when `i : Set.Iic j` -/ +def extendToSuccObjIso (i : Set.Iic j) : + (extendToSucc hj F τ).obj ⟨i, i.2.trans (Order.le_succ j)⟩ ≅ F.obj i := + extendToSucc.objIso F X i + +/-- The isomorphism `(extendToSucc hj F τ).obj ⟨Order.succ j, _⟩ ≅ X`. -/ +def extendToSuccObjSuccIso : + (extendToSucc hj F τ).obj ⟨Order.succ j, by simp⟩ ≅ X := + extendToSucc.objSuccIso hj F X + +@[reassoc] +lemma extendToSuccObjIso_hom_naturality (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : + (extendToSucc hj F τ).map (homOfLE hi : + ⟨i₁, hi.trans (hi₂.trans (Order.le_succ j))⟩ ⟶ ⟨i₂, hi₂.trans (Order.le_succ j)⟩) ≫ + (extendToSuccObjIso hj F τ ⟨i₂, hi₂⟩).hom = + (extendToSuccObjIso hj F τ ⟨i₁, hi.trans hi₂⟩).hom ≫ F.map (homOfLE hi) := by + dsimp [extendToSucc, extendToSuccObjIso] + rw [extendToSucc.map_eq _ _ _ _ _ _ hi₂, assoc, assoc, Iso.inv_hom_id, comp_id] + +/-- The isomorphism expressing that `extendToSucc hj F τ` extends `F`. -/ +@[simps!] +def extendToSuccRestrictionLEIso : + Iteration.restrictionLE (extendToSucc hj F τ) (Order.le_succ j) ≅ F := + NatIso.ofComponents (extendToSuccObjIso hj F τ) (by + rintro ⟨i₁, h₁⟩ ⟨i₂, h₂⟩ f + apply extendToSuccObjIso_hom_naturality) + +lemma extentToSucc_map (i₁ i₂ : J) (hi : i₁ ≤ i₂) (hi₂ : i₂ ≤ j) : + (extendToSucc hj F τ).map (homOfLE hi : + ⟨i₁, hi.trans (hi₂.trans (Order.le_succ j))⟩ ⟶ ⟨i₂, hi₂.trans (Order.le_succ j)⟩) = + (extendToSuccObjIso hj F τ ⟨i₁, hi.trans hi₂⟩).hom ≫ F.map (homOfLE hi) ≫ + (extendToSuccObjIso hj F τ ⟨i₂, hi₂⟩).inv := by + rw [← extendToSuccObjIso_hom_naturality_assoc, Iso.hom_inv_id, comp_id] + +lemma extendToSucc_map_le_succ : + (extendToSucc hj F τ).map (homOfLE (Order.le_succ j)) = + (extendToSuccObjIso hj F τ ⟨j, by simp⟩).hom ≫ τ ≫ + (extendToSuccObjSuccIso hj F τ).inv := + extendToSucc.map_self_succ _ _ _ + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean b/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean new file mode 100644 index 0000000000000..80bdbaec34cea --- /dev/null +++ b/Mathlib/CategoryTheory/SmallObject/Iteration/Nonempty.lean @@ -0,0 +1,97 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ +import Mathlib.CategoryTheory.SmallObject.Iteration.ExtendToSucc + +/-! +# Existence of objects in the category of iterations of functors + +Given a functor `Φ : C ⥤ C` and a natural transformation `ε : 𝟭 C ⟶ Φ`, +we shall show in this file that for any well ordered set `J`, +and `j : J`, the category `Functor.Iteration ε j` is nonempty. +As we already know from the main result in `SmallObject.Iteration.UniqueHom` +that such objects, if they exist, are unique up to a unique isomorphism, +we shall show the existence of a term in `Functor.Iteration ε j` by +transfinite induction. + +-/ + +universe u + +namespace CategoryTheory + +open Category Limits + +variable {C : Type*} [Category C] {Φ : C ⥤ C} {ε : 𝟭 C ⟶ Φ} + {J : Type u} [LinearOrder J] [OrderBot J] [SuccOrder J] + +namespace Functor + +namespace Iteration + +variable (ε J) in +/-- The obvious term in `Iteration ε ⊥`: it is given by the identity functor. -/ +def mkOfBot : Iteration ε (⊥ : J) where + F := (Functor.const _).obj (𝟭 C) + isoZero := Iso.refl _ + isoSucc _ h := by simp at h + mapSucc'_eq _ h := by simp at h + isColimit x hx h := by + exfalso + refine hx.not_isMin (by simpa using h) + +/-- When `j : J` is not maximal, this is the extension as `Iteration ε (Order.succ j)` +of any `iter : Iteration ε j`. -/ +noncomputable def mkOfSucc {j : J} (hj : ¬IsMax j) (iter : Iteration ε j) : + Iteration ε (Order.succ j) where + F := extendToSucc hj iter.F (whiskerLeft _ ε) + isoZero := (extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨⊥, by simp⟩).trans iter.isoZero + isoSucc i hi := + if hij : i < j then + extendToSuccObjIso _ _ _ ⟨Order.succ i, Order.succ_le_of_lt hij⟩ ≪≫ + iter.isoSucc i hij ≪≫ (isoWhiskerRight (extendToSuccObjIso _ _ _ ⟨i, hij.le⟩).symm _) + else + have hij' : i = j := le_antisymm + (by simpa only [Order.lt_succ_iff_of_not_isMax hj] using hi) (by simpa using hij) + eqToIso (by subst hij'; rfl) ≪≫ extendToSuccObjSuccIso hj iter.F (whiskerLeft _ ε) ≪≫ + isoWhiskerRight ((extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨j, by simp⟩).symm.trans + (eqToIso (by subst hij'; rfl))) _ + mapSucc'_eq i hi := by + obtain hi' | rfl := ((Order.lt_succ_iff_of_not_isMax hj).mp hi).lt_or_eq + · ext X + have := iter.mapSucc_eq i hi' + dsimp [mapSucc, mapSucc'] at this ⊢ + rw [extentToSucc_map _ _ _ _ _ _ (Order.succ_le_of_lt hi'), this, dif_pos hi'] + dsimp + rw [assoc, assoc] + erw [ε.naturality_assoc] + · ext X + dsimp [mapSucc'] + rw [dif_neg (gt_irrefl i), extendToSucc_map_le_succ] + dsimp + rw [id_comp, comp_id] + erw [ε.naturality_assoc] + isColimit i hi hij := by + have hij' : i ≤ j := by + obtain hij | rfl := hij.lt_or_eq + · exact (Order.lt_succ_iff_of_not_isMax hj).1 hij + · exfalso + exact Order.not_isSuccLimit_succ_of_not_isMax hj hi + refine (IsColimit.precomposeHomEquiv + (isoWhiskerLeft (monotone_inclusion_lt_le_of_le hij').functor + (extendToSuccRestrictionLEIso hj iter.F (whiskerLeft _ ε))).symm _).1 + (IsColimit.ofIsoColimit (iter.isColimit i hi hij') + (Iso.symm (Cocones.ext (extendToSuccObjIso hj iter.F (whiskerLeft _ ε) ⟨i, hij'⟩) + (fun ⟨k, hk⟩ ↦ ?_)))) + dsimp + rw [assoc, extendToSuccObjIso_hom_naturality hj iter.F (whiskerLeft _ ε)] + dsimp + rw [Iso.inv_hom_id_assoc] + +end Iteration + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/SmallObject/WellOrderInductionData.lean b/Mathlib/CategoryTheory/SmallObject/WellOrderInductionData.lean new file mode 100644 index 0000000000000..1c0de001e52da --- /dev/null +++ b/Mathlib/CategoryTheory/SmallObject/WellOrderInductionData.lean @@ -0,0 +1,272 @@ +/- +Copyright (c) 2024 Joël Riou. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Joël Riou +-/ + +import Mathlib.CategoryTheory.Category.Preorder +import Mathlib.CategoryTheory.Functor.Category +import Mathlib.CategoryTheory.Types +import Mathlib.Order.SuccPred.Limit + +/-! +# Limits of inverse systems indexed by well-ordered types + +Given a functor `F : Jᵒᵖ ⥤ Type v` where `J` is a well-ordered type, +we introduce a structure `F.WellOrderInductionData` which allows +to show that the map `F.sections → F.obj (op ⊥)` is surjective. + +The data and properties in `F.WellOrderInductionData` consist of a +section to the maps `F.obj (op (Order.succ j)) → F.obj (op j)` when `j` is not maximal, +and, when `j` is limit, a section to the canonical map from `F.obj (op j)` +to the type of compatible families of elements in `F.obj (op i)` for `i < j`. + +In other words, from `val₀ : F.obj (op ⊥)`, a term `d : F.WellOrderInductionData` +allows the construction, by transfinite induction, of a section of `F` +which restricts to `val₀`. + +-/ + +universe v u + +namespace CategoryTheory + +open Opposite + +namespace Functor + +variable {J : Type u} [LinearOrder J] [SuccOrder J] + (F : Jᵒᵖ ⥤ Type v) + +/-- Given a functor `F : Jᵒᵖ ⥤ Type v` where `J` is a well-ordered type, this data +allows to construct a section of `F` from an element in `F.obj (op ⊥)`, +see `WellOrderInductionData.sectionsMk`. -/ +structure WellOrderInductionData where + /-- A section `F.obj (op j) → F.obj (op (Order.succ j))` to the restriction + `F.obj (op (Order.succ j)) → F.obj (op j)` when `j` is not maximal. -/ + succ (j : J) (hj : ¬IsMax j) (x : F.obj (op j)) : F.obj (op (Order.succ j)) + map_succ (j : J) (hj : ¬IsMax j) (x : F.obj (op j)) : + F.map (homOfLE (Order.le_succ j)).op (succ j hj x) = x + /-- When `j` is a limit element, and `x` is a compatible family of elements + in `F.obj (op i)` for all `i < j`, this is a lifting to `F.obj (op j)`. -/ + lift (j : J) (hj : Order.IsSuccLimit j) + (x : ((OrderHom.Subtype.val (· ∈ Set.Iio j)).monotone.functor.op ⋙ F).sections) : + F.obj (op j) + map_lift (j : J) (hj : Order.IsSuccLimit j) + (x : ((OrderHom.Subtype.val (· ∈ Set.Iio j)).monotone.functor.op ⋙ F).sections) + (i : J) (hi : i < j) : + F.map (homOfLE hi.le).op (lift j hj x) = x.val (op ⟨i, hi⟩) + +namespace WellOrderInductionData + +variable {F} (d : F.WellOrderInductionData) [OrderBot J] + +/-- Given `d : F.WellOrderInductionData`, `val₀ : F.obj (op ⊥)` and `j : J`, +this is the data of an element `val : F.obj (op j)` such that the induced +compatible family of elements in all `F.obj (op i)` for `i ≤ j` +is determined by `val₀` and the choice of "liftings" given by `d`. -/ +structure Extension (val₀ : F.obj (op ⊥)) (j : J) where + /-- An element in `F.obj (op j)`, which, by restriction, induces elements + in `F.obj (op i)` for all `i ≤ j`. -/ + val : F.obj (op j) + map_zero : F.map (homOfLE bot_le).op val = val₀ + map_succ (i : J) (hi : i < j) : + F.map (homOfLE (Order.succ_le_of_lt hi)).op val = + d.succ i (not_isMax_iff.2 ⟨_, hi⟩) (F.map (homOfLE hi.le).op val) + map_limit (i : J) (hi : Order.IsSuccLimit i) (hij : i ≤ j) : + F.map (homOfLE hij).op val = d.lift i hi + { val := fun ⟨⟨k, hk⟩⟩ ↦ F.map (homOfLE (hk.le.trans hij)).op val + property := fun f ↦ by + dsimp + rw [← FunctorToTypes.map_comp_apply] + rfl } + +namespace Extension + +variable {d} {val₀ : F.obj (op ⊥)} + +/-- An element in `d.Extension val₀ j` induces an element in `d.Extension val₀ i` when `i ≤ j`. -/ +@[simps] +def ofLE {j : J} (e : d.Extension val₀ j) {i : J} (hij : i ≤ j) : d.Extension val₀ i where + val := F.map (homOfLE hij).op e.val + map_zero := by + rw [← FunctorToTypes.map_comp_apply] + exact e.map_zero + map_succ k hk := by + rw [← FunctorToTypes.map_comp_apply, ← FunctorToTypes.map_comp_apply, ← op_comp, ← op_comp, + homOfLE_comp, homOfLE_comp, e.map_succ k (lt_of_lt_of_le hk hij)] + map_limit k hk hki := by + rw [← FunctorToTypes.map_comp_apply, ← op_comp, homOfLE_comp, + e.map_limit k hk (hki.trans hij)] + congr + ext ⟨l, hl⟩ + dsimp + rw [← FunctorToTypes.map_comp_apply] + rfl + +lemma val_injective {j : J} {e e' : d.Extension val₀ j} (h : e.val = e'.val) : e = e' := by + cases e + cases e' + subst h + rfl + +instance [WellFoundedLT J] (j : J) : Subsingleton (d.Extension val₀ j) := by + induction j using SuccOrder.limitRecOn with + | hm i hi => + obtain rfl : i = ⊥ := by simpa using hi + refine Subsingleton.intro (fun e₁ e₂ ↦ val_injective ?_) + have h₁ := e₁.map_zero + have h₂ := e₂.map_zero + simp only [homOfLE_refl, op_id, FunctorToTypes.map_id_apply] at h₁ h₂ + rw [h₁, h₂] + | hs i hi hi' => + refine Subsingleton.intro (fun e₁ e₂ ↦ val_injective ?_) + have h₁ := e₁.map_succ i (Order.lt_succ_of_not_isMax hi) + have h₂ := e₂.map_succ i (Order.lt_succ_of_not_isMax hi) + simp only [homOfLE_refl, op_id, FunctorToTypes.map_id_apply, homOfLE_leOfHom] at h₁ h₂ + rw [h₁, h₂] + congr + exact congr_arg val + (Subsingleton.elim (e₁.ofLE (Order.le_succ i)) (e₂.ofLE (Order.le_succ i))) + | hl i hi hi' => + refine Subsingleton.intro (fun e₁ e₂ ↦ val_injective ?_) + have h₁ := e₁.map_limit i hi (by rfl) + have h₂ := e₂.map_limit i hi (by rfl) + simp only [homOfLE_refl, op_id, FunctorToTypes.map_id_apply, OrderHom.Subtype.val_coe, + comp_obj, op_obj, Monotone.functor_obj, homOfLE_leOfHom] at h₁ h₂ + rw [h₁, h₂] + congr + ext ⟨⟨l, hl⟩⟩ + have := hi' l hl + exact congr_arg val (Subsingleton.elim (e₁.ofLE hl.le) (e₂.ofLE hl.le)) + +lemma compatibility [WellFoundedLT J] + {j : J} (e : d.Extension val₀ j) {i : J} (e' : d.Extension val₀ i) (h : i ≤ j) : + F.map (homOfLE h).op e.val = e'.val := by + obtain rfl : e' = e.ofLE h := Subsingleton.elim _ _ + rfl + +variable (d val₀) in +/-- The obvious element in `d.Extension val₀ ⊥`. -/ +@[simps] +def zero : d.Extension val₀ ⊥ where + val := val₀ + map_zero := by simp + map_succ i hi := by simp at hi + map_limit i hi hij := by + obtain rfl : i = ⊥ := by simpa using hij + simpa using hi.not_isMin + +/-- The element in `d.Extension val₀ (Order.succ j)` obtained by extending +an element in `d.Extension val₀ j` when `j` is not maximal. -/ +def succ {j : J} (e : d.Extension val₀ j) (hj : ¬IsMax j) : + d.Extension val₀ (Order.succ j) where + val := d.succ j hj e.val + map_zero := by + simp only [← e.map_zero] + conv_rhs => rw [← d.map_succ j hj e.val] + rw [← FunctorToTypes.map_comp_apply] + rfl + map_succ i hi := by + obtain hij | rfl := ((Order.lt_succ_iff_of_not_isMax hj).mp hi).lt_or_eq + · rw [← homOfLE_comp ((Order.lt_succ_iff_of_not_isMax hj).mp hi) (Order.le_succ j), op_comp, + FunctorToTypes.map_comp_apply, d.map_succ, ← e.map_succ i hij, + ← homOfLE_comp (Order.succ_le_of_lt hij) (Order.le_succ j), op_comp, + FunctorToTypes.map_comp_apply, d.map_succ] + · simp only [homOfLE_refl, op_id, FunctorToTypes.map_id_apply, homOfLE_leOfHom, + d.map_succ] + map_limit i hi hij := by + obtain hij | rfl := hij.lt_or_eq + · have hij' : i ≤ j := (Order.lt_succ_iff_of_not_isMax hj).mp hij + have := congr_arg (F.map (homOfLE hij').op) (d.map_succ j hj e.val) + rw [e.map_limit i hi, ← FunctorToTypes.map_comp_apply, ← op_comp, homOfLE_comp] at this + rw [this] + congr + ext ⟨⟨l, hl⟩⟩ + dsimp + conv_lhs => rw [← d.map_succ j hj e.val] + rw [← FunctorToTypes.map_comp_apply] + rfl + · exfalso + exact hj hi.isMax + +variable [WellFoundedLT J] + +/-- When `j` is a limit element, this is the exntesion to `d.Extension val₀ j` +of a family of elements in `d.Extension val₀ i` for all `i < j`. -/ +def limit (j : J) (hj : Order.IsSuccLimit j) + (e : ∀ (i : J) (_ : i < j), d.Extension val₀ i) : + d.Extension val₀ j where + val := d.lift j hj + { val := fun ⟨i, hi⟩ ↦ (e i hi).val + property := fun f ↦ by apply compatibility } + map_zero := by + rw [d.map_lift _ _ _ _ (by simpa [bot_lt_iff_ne_bot] using hj.not_isMin)] + simpa only [homOfLE_refl, op_id, FunctorToTypes.map_id_apply] using + (e ⊥ (by simpa [bot_lt_iff_ne_bot] using hj.not_isMin)).map_zero + map_succ i hi := by + convert (e (Order.succ i) ((Order.IsSuccLimit.succ_lt_iff hj).mpr hi)).map_succ i + (by + simp only [Order.lt_succ_iff_not_isMax, not_isMax_iff] + exact ⟨_, hi⟩) using 1 + · dsimp + rw [FunctorToTypes.map_id_apply, + d.map_lift _ _ _ _ ((Order.IsSuccLimit.succ_lt_iff hj).mpr hi)] + · congr + rw [d.map_lift _ _ _ _ hi] + symm + apply compatibility + map_limit i hi hij := by + obtain hij' | rfl := hij.lt_or_eq + · have := (e i hij').map_limit i hi (by rfl) + dsimp at this ⊢ + rw [FunctorToTypes.map_id_apply] at this + rw [d.map_lift _ _ _ _ hij'] + dsimp + rw [this] + congr + dsimp + ext ⟨⟨l, hl⟩⟩ + rw [map_lift _ _ _ _ _ (hl.trans hij')] + apply compatibility + · dsimp + rw [FunctorToTypes.map_id_apply] + congr + ext ⟨⟨l, hl⟩⟩ + rw [d.map_lift _ _ _ _ hl] + +instance (j : J) : Nonempty (d.Extension val₀ j) := by + induction j using SuccOrder.limitRecOn with + | hm i hi => + obtain rfl : i = ⊥ := by simpa using hi + exact ⟨zero d val₀⟩ + | hs i hi hi' => exact ⟨hi'.some.succ hi⟩ + | hl i hi hi' => exact ⟨limit i hi (fun l hl ↦ (hi' l hl).some)⟩ + +noncomputable instance (j : J) : Unique (d.Extension val₀ j) := + uniqueOfSubsingleton (Nonempty.some inferInstance) + +end Extension + +variable [WellFoundedLT J] + +/-- When `J` is a well-ordered type, `F : Jᵒᵖ ⥤ Type v`, and `d : F.WellOrderInductionData`, +this is the section of `F` that is determined by `val₀ : F.obj (op ⊥)` -/ +noncomputable def sectionsMk (val₀ : F.obj (op ⊥)) : F.sections where + val j := (default : d.Extension val₀ j.unop).val + property := fun f ↦ by apply Extension.compatibility + +lemma sectionsMk_val_op_bot (val₀ : F.obj (op ⊥)) : + (d.sectionsMk val₀).val (op ⊥) = val₀ := by + simpa using (default : d.Extension val₀ ⊥).map_zero + +include d in +lemma surjective : + Function.Surjective ((fun s ↦ s (op ⊥)) ∘ Subtype.val : F.sections → F.obj (op ⊥)) := + fun val₀ ↦ ⟨d.sectionsMk val₀, d.sectionsMk_val_op_bot val₀⟩ + +end WellOrderInductionData + +end Functor + +end CategoryTheory diff --git a/Mathlib/CategoryTheory/Triangulated/Functor.lean b/Mathlib/CategoryTheory/Triangulated/Functor.lean index 884a5b5ce77dc..2bafc57433276 100644 --- a/Mathlib/CategoryTheory/Triangulated/Functor.lean +++ b/Mathlib/CategoryTheory/Triangulated/Functor.lean @@ -194,7 +194,7 @@ noncomputable instance [F.IsTriangulated] : comm₃ := by simp } exact isIso₂_of_isIso₁₃ φ (F.map_distinguished _ (binaryProductTriangle_distinguished X₁ X₃)) (binaryProductTriangle_distinguished _ _) - (by dsimp; infer_instance) (by dsimp; infer_instance) + (by dsimp [φ]; infer_instance) (by dsimp [φ]; infer_instance) instance (priority := 100) [F.IsTriangulated] : F.Additive := F.additive_of_preserves_binary_products diff --git a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean index 19ecd990580b6..2dd42b91269fb 100644 --- a/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean +++ b/Mathlib/Combinatorics/Additive/AP/Three/Behrend.lean @@ -42,6 +42,9 @@ integer points on that sphere and map them onto `ℕ` in a way that preserves ar 3AP-free, Salem-Spencer, Behrend construction, arithmetic progression, sphere, strictly convex -/ +assert_not_exists IsConformalMap +assert_not_exists Conformal + open Nat hiding log open Finset Metric Real open scoped Pointwise diff --git a/Mathlib/Combinatorics/Additive/CauchyDavenport.lean b/Mathlib/Combinatorics/Additive/CauchyDavenport.lean index c986855dbedef..ec8c94780e944 100644 --- a/Mathlib/Combinatorics/Additive/CauchyDavenport.lean +++ b/Mathlib/Combinatorics/Additive/CauchyDavenport.lean @@ -100,8 +100,8 @@ private lemma wellFoundedOn_devosMulRel : Set.WellFoundedOn.prod_lex_of_wellFoundedOn_fiber ?_ fun n ↦ wellFounded_lt.onFun.wellFoundedOn exact wellFounded_lt.onFun.wellFoundedOn.mono' fun x hx y _ ↦ tsub_lt_tsub_left_of_le <| - add_le_add ((card_le_card_mul_right _ hx.1.2).trans_eq hx.2) <| - (card_le_card_mul_left _ hx.1.1).trans_eq hx.2 + add_le_add ((card_le_card_mul_right hx.1.2).trans_eq hx.2) <| + (card_le_card_mul_left hx.1.1).trans_eq hx.2 /-- A generalisation of the **Cauchy-Davenport theorem** to arbitrary groups. The size of `s * t` is lower-bounded by `|s| + |t| - 1` unless this quantity is greater than the size of the smallest @@ -151,7 +151,7 @@ lemma cauchy_davenport_minOrder_mul (hs : s.Nonempty) (ht : t.Nonempty) : refine Or.inl ((minOrder_le_natCard (zpowers_ne_bot.2 hg) <| s.finite_toSet.smul_set.subset hS).trans <| WithTop.coe_le_coe.2 <| ((Nat.card_mono s.finite_toSet.smul_set hS).trans_eq <| ?_).trans <| - card_le_card_mul_right _ ht) + card_le_card_mul_right ht) rw [← coe_smul_finset] simp [-coe_smul_finset] -- Else, we can transform `s`, `t` to `s'`, `t'` and `s''`, `t''`, such that one of `(s', t')` and @@ -165,7 +165,7 @@ lemma cauchy_davenport_minOrder_mul (hs : s.Nonempty) (ht : t.Nonempty) : · rw [← card_smul_finset g⁻¹ t] refine Or.inr ((add_le_add_right hst _).trans ?_) rw [← card_union_of_disjoint hgt] - exact (card_le_card_mul_left _ hgs).trans (le_add_of_le_left aux1) + exact (card_le_card_mul_left hgs).trans (le_add_of_le_left aux1) -- Else, we're done by induction on either `(s', t')` or `(s'', t'')` depending on whether -- `|s| + |t| ≤ |s'| + |t'|` or `|s| + |t| < |s''| + |t''|`. One of those two inequalities must -- hold since `2 * (|s| + |t|) = |s'| + |t'| + |s''| + |t''|`. @@ -208,7 +208,7 @@ lemma cauchy_davenport_mul_of_linearOrder_isCancelMul [LinearOrder α] [Semigrou [MulLeftMono α] [MulRightMono α] {s t : Finset α} (hs : s.Nonempty) (ht : t.Nonempty) : #s + #t - 1 ≤ #(s * t) := by suffices s * {t.min' ht} ∩ ({s.max' hs} * t) = {s.max' hs * t.min' ht} by - rw [← card_singleton_mul t (s.max' hs), ← card_mul_singleton s (t.min' ht), + rw [← card_singleton_mul (s.max' hs) t, ← card_mul_singleton s (t.min' ht), ← card_union_add_card_inter, ← card_singleton _, ← this, Nat.add_sub_cancel] exact card_mono (union_subset (mul_subset_mul_left <| singleton_subset_iff.2 <| min'_mem _ _) <| mul_subset_mul_right <| singleton_subset_iff.2 <| max'_mem _ _) diff --git a/Mathlib/Combinatorics/Additive/CovBySMul.lean b/Mathlib/Combinatorics/Additive/CovBySMul.lean new file mode 100644 index 0000000000000..d85c2f8f8d894 --- /dev/null +++ b/Mathlib/Combinatorics/Additive/CovBySMul.lean @@ -0,0 +1,70 @@ +/- +Copyright (c) 2024 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Algebra.Group.Pointwise.Finset.Basic +import Mathlib.Data.Real.Basic + +/-! +# Relation of covering by cosets + +This file defines a predicate for a set to be covered by at most `K` cosets of another set. + +This is a fundamental relation to study in additive combinatorics. +-/ + +open scoped Finset Pointwise + +variable {M N X : Type*} [Monoid M] [Monoid N] [MulAction M X] [MulAction N X] {K L : ℝ} + {A A₁ A₂ B B₁ B₂ C : Set X} + +variable (M) in +/-- Predicate for a set `A` to be covered by at most `K` cosets of another set `B` under the action +by the monoid `M`. -/ +@[to_additive "Predicate for a set `A` to be covered by at most `K` cosets of another set `B` under +the action by the monoid `M`."] +def CovBySMul (K : ℝ) (A B : Set X) : Prop := ∃ F : Finset M, #F ≤ K ∧ A ⊆ (F : Set M) • B + +@[to_additive (attr := simp, refl)] +lemma CovBySMul.rfl : CovBySMul M 1 A A := ⟨1, by simp⟩ + +@[to_additive (attr := simp)] +lemma CovBySMul.of_subset (hAB : A ⊆ B) : CovBySMul M 1 A B := ⟨1, by simpa⟩ + +@[to_additive] lemma CovBySMul.nonneg : CovBySMul M K A B → 0 ≤ K := by + rintro ⟨F, hF, -⟩; exact (#F).cast_nonneg.trans hF + +@[to_additive (attr := simp)] +lemma covBySMul_zero : CovBySMul M 0 A B ↔ A = ∅ := by simp [CovBySMul] + +@[to_additive] +lemma CovBySMul.mono (hKL : K ≤ L) : CovBySMul M K A B → CovBySMul M L A B := by + rintro ⟨F, hF, hFAB⟩; exact ⟨F, hF.trans hKL, hFAB⟩ + +@[to_additive] lemma CovBySMul.trans [MulAction M N] [IsScalarTower M N X] + (hAB : CovBySMul M K A B) (hBC : CovBySMul N L B C) : CovBySMul N (K * L) A C := by + classical + have := hAB.nonneg + obtain ⟨F₁, hF₁, hFAB⟩ := hAB + obtain ⟨F₂, hF₂, hFBC⟩ := hBC + refine ⟨F₁ • F₂, ?_, ?_⟩ + · calc + (#(F₁ • F₂) : ℝ) ≤ #F₁ * #F₂ := mod_cast Finset.card_smul_le + _ ≤ K * L := by gcongr + · calc + A ⊆ (F₁ : Set M) • B := hFAB + _ ⊆ (F₁ : Set M) • (F₂ : Set N) • C := by gcongr + _ = (↑(F₁ • F₂) : Set N) • C := by simp + +@[to_additive] +lemma CovBySMul.subset_left (hA : A₁ ⊆ A₂) (hAB : CovBySMul M K A₂ B) : + CovBySMul M K A₁ B := by simpa using (CovBySMul.of_subset (M := M) hA).trans hAB + +@[to_additive] +lemma CovBySMul.subset_right (hB : B₁ ⊆ B₂) (hAB : CovBySMul M K A B₁) : + CovBySMul M K A B₂ := by simpa using hAB.trans (.of_subset (M := M) hB) + +@[to_additive] +lemma CovBySMul.subset (hA : A₁ ⊆ A₂) (hB : B₁ ⊆ B₂) (hAB : CovBySMul M K A₂ B₁) : + CovBySMul M K A₁ B₂ := (hAB.subset_left hA).subset_right hB diff --git a/Mathlib/Combinatorics/Additive/Energy.lean b/Mathlib/Combinatorics/Additive/Energy.lean index 2cd35ab13760c..e1f1d36d3e389 100644 --- a/Mathlib/Combinatorics/Additive/Energy.lean +++ b/Mathlib/Combinatorics/Additive/Energy.lean @@ -178,7 +178,7 @@ lemma mulEnergy_univ_left : Eₘ[univ, t] = Fintype.card α * t.card ^ 2 := by let f : α × α × α → (α × α) × α × α := fun x => ((x.1 * x.2.2, x.1 * x.2.1), x.2) have : (↑((univ : Finset α) ×ˢ t ×ˢ t) : Set (α × α × α)).InjOn f := by rintro ⟨a₁, b₁, c₁⟩ _ ⟨a₂, b₂, c₂⟩ h₂ h - simp_rw [Prod.ext_iff] at h + simp_rw [f, Prod.ext_iff] at h obtain ⟨h, rfl, rfl⟩ := h rw [mul_right_cancel h.1] rw [← card_image_of_injOn this] @@ -187,7 +187,7 @@ lemma mulEnergy_univ_left : Eₘ[univ, t] = Fintype.card α * t.card ^ 2 := by Prod.exists] refine ⟨fun h => ⟨a.1.1 * a.2.2⁻¹, _, _, h.1, by simp [f, mul_right_comm, h.2]⟩, ?_⟩ rintro ⟨b, c, d, hcd, rfl⟩ - simpa [mul_right_comm] + simpa [f, mul_right_comm] @[to_additive (attr := simp)] lemma mulEnergy_univ_right : Eₘ[s, univ] = Fintype.card α * s.card ^ 2 := by diff --git a/Mathlib/Combinatorics/Additive/FreimanHom.lean b/Mathlib/Combinatorics/Additive/FreimanHom.lean index 804e026e94c5a..b3ec72a21f901 100644 --- a/Mathlib/Combinatorics/Additive/FreimanHom.lean +++ b/Mathlib/Combinatorics/Additive/FreimanHom.lean @@ -284,8 +284,8 @@ lemma IsMulFreimanHom.mono (hmn : m ≤ n) (hf : IsMulFreimanHom n A B f) : obtain ha | ha := ha · exact htA ha · rwa [eq_of_mem_replicate ha] - · rw [_root_.map_add, card_replicate, hs, Nat.add_sub_cancel' hmn] - · rw [_root_.map_add, card_replicate, ht, Nat.add_sub_cancel' hmn] + · rw [card_add, card_replicate, hs, Nat.add_sub_cancel' hmn] + · rw [card_add, card_replicate, ht, Nat.add_sub_cancel' hmn] · rw [prod_add, prod_add, h] end CancelCommMonoid @@ -317,8 +317,8 @@ lemma IsMulFreimanIso.mono {hmn : m ≤ n} (hf : IsMulFreimanIso n A B f) : obtain ha | ha := ha · exact htA ha · rwa [eq_of_mem_replicate ha] - · rw [_root_.map_add, card_replicate, hs, Nat.add_sub_cancel' hmn] - · rw [_root_.map_add, card_replicate, ht, Nat.add_sub_cancel' hmn] + · rw [card_add, card_replicate, hs, Nat.add_sub_cancel' hmn] + · rw [card_add, card_replicate, ht, Nat.add_sub_cancel' hmn] end CancelCommMonoid diff --git a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean index 0a386abf7a0f9..99b4e12ea6411 100644 --- a/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean +++ b/Mathlib/Combinatorics/Additive/PluenneckeRuzsa.lean @@ -177,14 +177,14 @@ theorem ruzsa_triangle_inequality_mul_mul_mul (A B C : Finset G) : rw [mem_erase, mem_powerset, ← nonempty_iff_ne_empty] at hU refine cast_le.1 (?_ : (_ : ℚ≥0) ≤ _) push_cast - refine (le_div_iff₀ <| cast_pos.2 hB.card_pos).1 ?_ - rw [mul_div_right_comm, mul_comm _ B] - refine (Nat.cast_le.2 <| card_le_card_mul_left _ hU.1).trans ?_ + rw [← le_div_iff₀ (cast_pos.2 hB.card_pos), mul_div_right_comm, mul_comm _ B] + refine (Nat.cast_le.2 <| card_le_card_mul_left hU.1).trans ?_ refine le_trans ?_ (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 ?_ + #adaptation_note /-- 2024-11-01 `le_div_iff₀` is synthesizing wrong `GroupWithZero` without `@` -/ + rw [← mul_div_right_comm, ← mul_assoc, + @le_div_iff₀ _ (_) _ _ _ _ _ _ _ (cast_pos.2 hU.1.card_pos)] exact mod_cast pluennecke_petridis_inequality_mul C (mul_aux hU.1 hU.2 hUA) /-- **Ruzsa's triangle inequality**. Mul-div-div version. -/ diff --git a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean index 825ab42bd37ab..3bbb14e93b8e0 100644 --- a/Mathlib/Combinatorics/Additive/RuzsaCovering.lean +++ b/Mathlib/Combinatorics/Additive/RuzsaCovering.lean @@ -49,8 +49,12 @@ theorem ruzsa_covering_mul (hB : B.Nonempty) (hK : #(A * B) ≤ K * #B) : obtain ⟨b, hb, c, hc₁, hc₂⟩ := H exact mem_mul.2 ⟨b, hb, b⁻¹ * a, mem_div.2 ⟨_, hc₂, _, hc₁, by simp⟩, by simp⟩ -@[to_additive (attr := deprecated (since := "2024-11-26"))] +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +@[to_additive] alias exists_subset_mul_div := ruzsa_covering_mul +attribute [deprecated ruzsa_covering_mul (since := "2024-11-26")] exists_subset_mul_div +attribute [deprecated ruzsa_covering_add (since := "2024-11-26")] exists_subset_add_sub end Finset @@ -68,7 +72,11 @@ lemma ruzsa_covering_mul (hA : A.Finite) (hB : B.Finite) (hB₀ : B.Nonempty) obtain ⟨F, hFA, hF, hAF⟩ := Finset.ruzsa_covering_mul hB₀ (by simpa [← Finset.coe_mul] using hK) exact ⟨F, by norm_cast; simp [*]⟩ -@[to_additive (attr := deprecated (since := "2024-11-26"))] +-- `alias` doesn't add the deprecation suggestion to the `to_additive` version +-- see https://github.com/leanprover-community/mathlib4/issues/19424 +@[to_additive] alias exists_subset_mul_div := ruzsa_covering_mul +attribute [deprecated ruzsa_covering_mul (since := "2024-11-26")] exists_subset_mul_div +attribute [deprecated ruzsa_covering_add (since := "2024-11-26")] exists_subset_add_sub end Set diff --git a/Mathlib/Combinatorics/Additive/VerySmallDoubling.lean b/Mathlib/Combinatorics/Additive/VerySmallDoubling.lean new file mode 100644 index 0000000000000..b6015f656048d --- /dev/null +++ b/Mathlib/Combinatorics/Additive/VerySmallDoubling.lean @@ -0,0 +1,62 @@ +/- +Copyright (c) 2024 Yaël Dillies, Patrick Luo. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies, Patrick Luo +-/ +import Mathlib.Algebra.Group.Pointwise.Finset.Basic +import Mathlib.GroupTheory.GroupAction.Defs + +/-! +# Sets with very small doubling + +This file characterises sets with no doubling (finsets `A` such that `#(A ^ 2) = #A`) as the sets +which are either empty or translates of a subgroup. + +For the converse, use the existing facts from the pointwise API: `∅ ^ 2 = ∅` (`Finset.empty_pow`), +`(a • H) ^ 2 = a ^ 2 • H ^ 2 = a ^ 2 • H` (`smul_pow`, `coe_set_pow`) + +## TODO + +* Do we need a version stated using the doubling constant (`Finset.mulConst`)? +* Add characterisation for sets with doubling < 3/2 +-/ + +open MulOpposite MulAction +open scoped Pointwise RightActions + +namespace Finset +variable {G : Type*} [Group G] [DecidableEq G] {A : Finset G} + +/-- A set with no doubling is either empty or the translate of a subgroup. + +Precisely, if `A` has no doubling then there exists a subgroup `H` such `aH = Ha = A` for all +`a ∈ A`. -/ +@[to_additive "A set with no doubling is either empty or the translate of a subgroup. + +Precisely, if `A` has no doubling then there exists a subgroup `H` such `a + H = H + a = A` for all +`a ∈ A`."] +lemma exists_subgroup_of_no_doubling (hA : #(A * A) ≤ #A) : + ∃ H : Subgroup G, ∀ a ∈ A, a •> (H : Set G) = A ∧ (H : Set G) <• a = A := by + have smul_A {a} (ha : a ∈ A) : a •> A = A * A := + eq_of_subset_of_card_le (smul_finset_subset_mul ha) (by simpa) + have A_smul {a} (ha : a ∈ A) : A <• a = A * A := + eq_of_subset_of_card_le (op_smul_finset_subset_mul ha) (by simpa) + have smul_A_eq_op_smul_A {a} (ha : a ∈ A) : a •> A = A <• a := by rw [smul_A ha, A_smul ha] + have smul_A_eq_op_smul_A' {a} (ha : a ∈ A) : a⁻¹ •> A = A <• a⁻¹ := by + rw [inv_smul_eq_iff, smul_comm, smul_A_eq_op_smul_A ha, op_inv, inv_smul_smul] + let H := stabilizer G A + have inv_smul_A {a} (ha : a ∈ A) : a⁻¹ • (A : Set G) = H := by + ext x + refine ⟨?_, fun hx ↦ ?_⟩ + · rintro ⟨b, hb, rfl⟩ + simp [H, mul_smul, inv_smul_eq_iff, smul_A ha, smul_A hb] + · norm_cast + rwa [smul_A_eq_op_smul_A' ha, op_inv, mem_inv_smul_finset_iff, op_smul_eq_mul, ← smul_eq_mul, + ← mem_inv_smul_finset_iff, inv_mem hx] + refine ⟨H, fun a ha ↦ ⟨?_, ?_⟩⟩ + · rw [← inv_smul_A ha, smul_inv_smul] + · rw [← inv_smul_A ha, smul_comm] + norm_cast + rw [← smul_A_eq_op_smul_A ha, inv_smul_smul] + +end Finset diff --git a/Mathlib/Combinatorics/Colex.lean b/Mathlib/Combinatorics/Colex.lean index b828869fcbf1e..98e0a7d8d89ae 100644 --- a/Mathlib/Combinatorics/Colex.lean +++ b/Mathlib/Combinatorics/Colex.lean @@ -220,11 +220,11 @@ variable [DecidableEq α] instance instDecidableEq : DecidableEq (Colex α) := fun s t ↦ decidable_of_iff' (s.ofColex = t.ofColex) Colex.ext_iff -instance instDecidableLE [@DecidableRel α (· ≤ ·)] : @DecidableRel (Colex α) (· ≤ ·) := fun s t ↦ - decidable_of_iff' +instance instDecidableLE [DecidableRel (α := α) (· ≤ ·)] : DecidableRel (α := Colex α) (· ≤ ·) := + fun s t ↦ decidable_of_iff' (∀ ⦃a⦄, a ∈ ofColex s → a ∉ ofColex t → ∃ b, b ∈ ofColex t ∧ b ∉ ofColex s ∧ a ≤ b) Iff.rfl -instance instDecidableLT [@DecidableRel α (· ≤ ·)] : @DecidableRel (Colex α) (· < ·) := +instance instDecidableLT [DecidableRel (α := α) (· ≤ ·)] : DecidableRel (α := Colex α) (· < ·) := decidableLTOfDecidableLE /-- The colexigraphic order is insensitive to removing the same elements from both sets. -/ @@ -534,7 +534,7 @@ theorem geomSum_injective {n : ℕ} (hn : 2 ≤ n) : geomSum_le_geomSum_iff_toColex_le_toColex hn, ← le_antisymm_iff, Colex.toColex.injEq] at h theorem lt_geomSum_of_mem {a : ℕ} (hn : 2 ≤ n) (hi : a ∈ s) : a < ∑ i in s, n ^ i := - (Nat.lt_pow_self hn a).trans_le <| single_le_sum (by simp) hi + (a.lt_pow_self hn).trans_le <| single_le_sum (by simp) hi @[simp] theorem toFinset_bitIndices_twoPowSum (s : Finset ℕ) : (∑ i in s, 2 ^ i).bitIndices.toFinset = s := by diff --git a/Mathlib/Combinatorics/Enumerative/Catalan.lean b/Mathlib/Combinatorics/Enumerative/Catalan.lean index 21a578fab89bf..d7dd958d1d693 100644 --- a/Mathlib/Combinatorics/Enumerative/Catalan.lean +++ b/Mathlib/Combinatorics/Enumerative/Catalan.lean @@ -30,7 +30,7 @@ triangulations of convex polygons. * `catalan_eq_centralBinom_div`: The explicit formula for the Catalan number using the central binomial coefficient, `catalan n = Nat.centralBinom n / (n + 1)`. -* `treesOfNodesEq_card_eq_catalan`: The number of binary trees with `n` internal nodes +* `treesOfNumNodesEq_card_eq_catalan`: The number of binary trees with `n` internal nodes is `catalan n` ## Implementation details diff --git a/Mathlib/Combinatorics/Enumerative/Composition.lean b/Mathlib/Combinatorics/Enumerative/Composition.lean index 986e40eed5b1b..e1bf3970d658a 100644 --- a/Mathlib/Combinatorics/Enumerative/Composition.lean +++ b/Mathlib/Combinatorics/Enumerative/Composition.lean @@ -150,7 +150,7 @@ theorem sum_blocksFun : ∑ i, c.blocksFun i = n := by conv_rhs => rw [← c.blocks_sum, ← ofFn_blocksFun, sum_ofFn] theorem blocksFun_mem_blocks (i : Fin c.length) : c.blocksFun i ∈ c.blocks := - get_mem _ _ _ + get_mem _ _ @[simp] theorem one_le_blocks {i : ℕ} (h : i ∈ c.blocks) : 1 ≤ i := @@ -158,7 +158,7 @@ theorem one_le_blocks {i : ℕ} (h : i ∈ c.blocks) : 1 ≤ i := @[simp] theorem one_le_blocks' {i : ℕ} (h : i < c.length) : 1 ≤ c.blocks[i] := - c.one_le_blocks (get_mem (blocks c) i h) + c.one_le_blocks (get_mem (blocks c) _) @[simp] theorem blocks_pos' (i : ℕ) (h : i < c.length) : 0 < c.blocks[i] := diff --git a/Mathlib/Combinatorics/Enumerative/IncidenceAlgebra.lean b/Mathlib/Combinatorics/Enumerative/IncidenceAlgebra.lean index 08a4f0b16172f..cb22ef58fde04 100644 --- a/Mathlib/Combinatorics/Enumerative/IncidenceAlgebra.lean +++ b/Mathlib/Combinatorics/Enumerative/IncidenceAlgebra.lean @@ -321,7 +321,7 @@ instance algebraRight [PartialOrder α] [LocallyFiniteOrder α] [DecidableEq α] /-! ### The Lambda function -/ section Lambda -variable (𝕜) [Zero 𝕜] [One 𝕜] [Preorder α] [@DecidableRel α (· ⩿ ·)] +variable (𝕜) [Zero 𝕜] [One 𝕜] [Preorder α] [DecidableRel (α := α) (· ⩿ ·)] /-- The lambda function of the incidence algebra is the function that assigns `1` to every nonempty interval of cardinality one or two. -/ @@ -334,7 +334,7 @@ end Lambda /-! ### The Zeta and Möbius functions -/ section Zeta -variable (𝕜) [Zero 𝕜] [One 𝕜] [LE α] [@DecidableRel α (· ≤ ·)] {a b : α} +variable (𝕜) [Zero 𝕜] [One 𝕜] [LE α] [DecidableRel (α := α) (· ≤ ·)] {a b : α} /-- The zeta function of the incidence algebra is the function that assigns 1 to every nonempty interval, convolution with this function sums functions over intervals. -/ @@ -348,15 +348,16 @@ lemma zeta_of_le (h : a ≤ b) : zeta 𝕜 a b = 1 := if_pos h end Zeta -lemma zeta_mul_zeta [Semiring 𝕜] [Preorder α] [LocallyFiniteOrder α] [@DecidableRel α (· ≤ ·)] +lemma zeta_mul_zeta [Semiring 𝕜] [Preorder α] [LocallyFiniteOrder α] [DecidableRel (α := α) (· ≤ ·)] (a b : α) : (zeta 𝕜 * zeta 𝕜 : IncidenceAlgebra 𝕜 α) a b = (Icc a b).card := by rw [mul_apply, card_eq_sum_ones, Nat.cast_sum, Nat.cast_one] refine sum_congr rfl fun x hx ↦ ?_ rw [mem_Icc] at hx rw [zeta_of_le hx.1, zeta_of_le hx.2, one_mul] -lemma zeta_mul_kappa [Semiring 𝕜] [Preorder α] [LocallyFiniteOrder α] [@DecidableRel α (· ≤ ·)] - (a b : α) : (zeta 𝕜 * zeta 𝕜 : IncidenceAlgebra 𝕜 α) a b = (Icc a b).card := by +lemma zeta_mul_kappa [Semiring 𝕜] [Preorder α] [LocallyFiniteOrder α] + [DecidableRel (α := α) (· ≤ ·)] (a b : α) : + (zeta 𝕜 * zeta 𝕜 : IncidenceAlgebra 𝕜 α) a b = (Icc a b).card := by rw [mul_apply, card_eq_sum_ones, Nat.cast_sum, Nat.cast_one] refine sum_congr rfl fun x hx ↦ ?_ rw [mem_Icc] at hx @@ -474,7 +475,7 @@ end Mu'Spec section MuZeta variable (𝕜 α) [AddCommGroup 𝕜] [MulOneClass 𝕜] [PartialOrder α] [LocallyFiniteOrder α] - [DecidableEq α] [@DecidableRel α (· ≤ ·)] + [DecidableEq α] [DecidableRel (α := α) (· ≤ ·)] lemma mu_mul_zeta : (mu 𝕜 * zeta 𝕜 : IncidenceAlgebra 𝕜 α) = 1 := by ext a b @@ -500,7 +501,7 @@ private lemma mu_eq_mu' : (mu 𝕜 : IncidenceAlgebra 𝕜 α) = mu' 𝕜 := by lemma mu_eq_neg_sum_Ioc_of_ne (hab : a ≠ b) : mu 𝕜 a b = -∑ x ∈ Ioc a b, mu 𝕜 x b := by rw [mu_eq_mu', mu'_eq_sum_Ioc_of_ne hab] -lemma zeta_mul_mu [@DecidableRel α (· ≤ ·)] : (zeta 𝕜 * mu 𝕜 : IncidenceAlgebra 𝕜 α) = 1 := by +lemma zeta_mul_mu [DecidableRel (α := α) (· ≤ ·)] : (zeta 𝕜 * mu 𝕜 : IncidenceAlgebra 𝕜 α) = 1 := by rw [mu_eq_mu', zeta_mul_mu'] lemma sum_Icc_mu_left (a b : α) : ∑ x ∈ Icc a b, mu 𝕜 x b = if a = b then 1 else 0 := by @@ -513,7 +514,7 @@ variable (𝕜) [Ring 𝕜] [PartialOrder α] [LocallyFiniteOrder α] [Decidable @[simp] lemma mu_toDual (a b : α) : mu 𝕜 (toDual a) (toDual b) = mu 𝕜 b a := by - letI : @DecidableRel α (· ≤ ·) := Classical.decRel _ + letI : DecidableRel (α := α) (· ≤ ·) := Classical.decRel _ let mud : IncidenceAlgebra 𝕜 αᵒᵈ := { toFun := fun a b ↦ mu 𝕜 (ofDual b) (ofDual a) eq_zero_of_not_le' := fun a b hab ↦ apply_eq_zero_of_not_le (by exact hab) _ } @@ -544,7 +545,7 @@ variable [Ring 𝕜] [PartialOrder α] [OrderTop α] [LocallyFiniteOrder α] [De O'Donnell. -/ lemma moebius_inversion_top (f g : α → 𝕜) (h : ∀ x, g x = ∑ y ∈ Ici x, f y) (x : α) : f x = ∑ y ∈ Ici x, mu 𝕜 x y * g y := by - letI : @DecidableRel α (· ≤ ·) := Classical.decRel _ + letI : DecidableRel (α := α) (· ≤ ·) := Classical.decRel _ symm calc ∑ y ∈ Ici x, mu 𝕜 x y * g y = ∑ y ∈ Ici x, mu 𝕜 x y * ∑ z ∈ Ici y, f z := by simp_rw [h] @@ -554,8 +555,8 @@ lemma moebius_inversion_top (f g : α → 𝕜) (h : ∀ x, g x = ∑ y ∈ Ici rw [zeta_apply, if_pos (mem_Ici.mp ‹_›), one_mul] _ = ∑ y ∈ Ici x, ∑ z ∈ Ici y, mu 𝕜 x y * zeta 𝕜 y z * f z := by simp [mul_sum] _ = ∑ z ∈ Ici x, ∑ y ∈ Icc x z, mu 𝕜 x y * zeta 𝕜 y z * f z := by - erw [sum_sigma' (Ici x) fun y ↦ Ici y] - erw [sum_sigma' (Ici x) fun z ↦ Icc x z] + rw [sum_sigma' (Ici x) fun y ↦ Ici y] + rw [sum_sigma' (Ici x) fun z ↦ Icc x z] simp only [mul_boole, MulZeroClass.zero_mul, ite_mul, zeta_apply] apply sum_nbij' (fun ⟨a, b⟩ ↦ ⟨b, a⟩) (fun ⟨a, b⟩ ↦ ⟨b, a⟩) <;> aesop (add simp mul_assoc) (add unsafe le_trans) @@ -612,7 +613,8 @@ lemma prod_mk (a₁ a₂ : α) (b₁ b₂ : β) : f.prod g (a₁, b₁) (a₂, b @[simp] lemma prod_apply (x y : α × β) : f.prod g x y = f x.1 y.1 * g x.2 y.2 := rfl /-- This is a version of `IncidenceAlgebra.prod_mul_prod` that works over non-commutative rings. -/ -lemma prod_mul_prod' [LocallyFiniteOrder α] [LocallyFiniteOrder β] [@DecidableRel (α × β) (· ≤ ·)] +lemma prod_mul_prod' [LocallyFiniteOrder α] [LocallyFiniteOrder β] + [DecidableRel (α := α × β) (· ≤ ·)] (h : ∀ a₁ a₂ a₃ b₁ b₂ b₃, f₁ a₁ a₂ * g₁ b₁ b₂ * (f₂ a₂ a₃ * g₂ b₂ b₃) = f₁ a₁ a₂ * f₂ a₂ a₃ * (g₁ b₁ b₂ * g₂ b₂ b₃)) : f₁.prod g₁ * f₂.prod g₂ = (f₁ * f₂).prod (g₁ * g₂) := by @@ -624,7 +626,7 @@ lemma one_prod_one [DecidableEq α] [DecidableEq β] : ext x y; simp [Prod.ext_iff, ← ite_and, and_comm] @[simp] -lemma zeta_prod_zeta [@DecidableRel α (· ≤ ·)] [@DecidableRel β (· ≤ ·)] : +lemma zeta_prod_zeta [DecidableRel (α := α) (· ≤ ·)] [DecidableRel (α := β) (· ≤ ·)] : (zeta 𝕜).prod (zeta 𝕜) = (zeta 𝕜 : IncidenceAlgebra 𝕜 (α × β)) := by ext x y hxy; simp [hxy, hxy.1, hxy.2] @@ -632,7 +634,7 @@ end Ring section CommRing variable [CommRing 𝕜] [Preorder α] [Preorder β] [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [@DecidableRel (α × β) (· ≤ ·)] (f₁ f₂ : IncidenceAlgebra 𝕜 α) (g₁ g₂ : IncidenceAlgebra 𝕜 β) + [DecidableRel (α := α × β) (· ≤ ·)] (f₁ f₂ : IncidenceAlgebra 𝕜 α) (g₁ g₂ : IncidenceAlgebra 𝕜 β) @[simp] lemma prod_mul_prod : f₁.prod g₁ * f₂.prod g₂ = (f₁ * f₂).prod (g₁ * g₂) := diff --git a/Mathlib/Combinatorics/Extremal/RuzsaSzemeredi.lean b/Mathlib/Combinatorics/Extremal/RuzsaSzemeredi.lean new file mode 100644 index 0000000000000..59c4a36c6596f --- /dev/null +++ b/Mathlib/Combinatorics/Extremal/RuzsaSzemeredi.lean @@ -0,0 +1,269 @@ +/- +Copyright (c) 2022 Yaël Dillies. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Yaël Dillies +-/ +import Mathlib.Combinatorics.Additive.AP.Three.Behrend +import Mathlib.Combinatorics.SimpleGraph.Triangle.Tripartite +import Mathlib.Tactic.Rify + +/-! +# The Ruzsa-Szemerédi problem + +This file proves the lower bound of the Ruzsa-Szemerédi problem. The problem is to find the maximum +number of edges that a graph on `n` vertices can have if all edges belong to at most one triangle. + +The lower bound comes from turning the big 3AP-free set from Behrend's construction into a graph +that has the property that every triangle gives a (possibly trivial) arithmetic progression on the +original set. + +## Main declarations + +* `ruzsaSzemerediNumberNat n`: Maximum number of edges a graph on `n` vertices can have such that + each edge belongs to exactly one triangle. +* `ruzsaSzemerediNumberNat_asymptotic_lower_bound`: There exists a graph with `n` vertices and + `Ω((n ^ 2 * exp (-4 * sqrt (log n))))` edges such that each edge belongs to exactly one triangle. +-/ + +open Finset Nat Real SimpleGraph Sum3 SimpleGraph.TripartiteFromTriangles +open Fintype (card) +open scoped Pointwise + +variable {α β : Type*} + +/-! ### The Ruzsa-Szemerédi number -/ + +section ruzsaSzemerediNumber +variable [DecidableEq α] [DecidableEq β] [Fintype α] [Fintype β] {G H : SimpleGraph α} + +variable (α) in +/-- The **Ruzsa-Szemerédi number** of a fintype is the maximum number of edges a locally linear +graph on that type can have. + +In other words, `ruzsaSzemerediNumber α` is the maximum number of edges a graph on `α` can have such +that each edge belongs to exactly one triangle. -/ +noncomputable def ruzsaSzemerediNumber : ℕ := by + classical + exact Nat.findGreatest (fun m ↦ ∃ (G : SimpleGraph α) (_ : DecidableRel G.Adj), + #(G.cliqueFinset 3) = m ∧ G.LocallyLinear) ((card α).choose 3) + +open scoped Classical in +lemma ruzsaSzemerediNumber_le : ruzsaSzemerediNumber α ≤ (card α).choose 3 := Nat.findGreatest_le _ + +lemma ruzsaSzemerediNumber_spec : + ∃ (G : SimpleGraph α) (_ : DecidableRel G.Adj), + #(G.cliqueFinset 3) = ruzsaSzemerediNumber α ∧ G.LocallyLinear := by + classical + exact @Nat.findGreatest_spec _ + (fun m ↦ ∃ (G : SimpleGraph α) (_ : DecidableRel G.Adj), + #(G.cliqueFinset 3) = m ∧ G.LocallyLinear) _ _ (Nat.zero_le _) + ⟨⊥, inferInstance, by simp, locallyLinear_bot⟩ + +variable {n : ℕ} + +lemma SimpleGraph.LocallyLinear.le_ruzsaSzemerediNumber [DecidableRel G.Adj] + (hG : G.LocallyLinear) : #(G.cliqueFinset 3) ≤ ruzsaSzemerediNumber α := by + classical + exact le_findGreatest card_cliqueFinset_le ⟨G, inferInstance, by congr, hG⟩ + +lemma ruzsaSzemerediNumber_mono (f : α ↪ β) : ruzsaSzemerediNumber α ≤ ruzsaSzemerediNumber β := by + classical + refine findGreatest_mono ?_ (choose_mono _ <| Fintype.card_le_of_embedding f) + rintro n ⟨G, _, rfl, hG⟩ + refine ⟨G.map f, inferInstance, ?_, hG.map _⟩ + rw [← card_map ⟨map f, Finset.map_injective _⟩, ← cliqueFinset_map G f] + decide + +lemma ruzsaSzemerediNumber_congr (e : α ≃ β) : ruzsaSzemerediNumber α = ruzsaSzemerediNumber β := + (ruzsaSzemerediNumber_mono (e : α ↪ β)).antisymm <| ruzsaSzemerediNumber_mono e.symm + +/-- The `n`-th **Ruzsa-Szemerédi number** is the maximum number of edges a locally linear graph on +`n` vertices can have. + +In other words, `ruzsaSzemerediNumberNat n` is the maximum number of edges a graph on `n` vertices +can have such that each edge belongs to exactly one triangle. -/ +noncomputable def ruzsaSzemerediNumberNat (n : ℕ) : ℕ := ruzsaSzemerediNumber (Fin n) + +@[simp] +lemma ruzsaSzemerediNumberNat_card : ruzsaSzemerediNumberNat (card α) = ruzsaSzemerediNumber α := + ruzsaSzemerediNumber_congr (Fintype.equivFin _).symm + +lemma ruzsaSzemerediNumberNat_mono : Monotone ruzsaSzemerediNumberNat := fun _m _n h => + ruzsaSzemerediNumber_mono (Fin.castLEEmb h) + +lemma ruzsaSzemerediNumberNat_le : ruzsaSzemerediNumberNat n ≤ n.choose 3 := + ruzsaSzemerediNumber_le.trans_eq <| by rw [Fintype.card_fin] + +@[simp] lemma ruzsaSzemerediNumberNat_zero : ruzsaSzemerediNumberNat 0 = 0 := + le_zero_iff.1 ruzsaSzemerediNumberNat_le + +@[simp] lemma ruzsaSzemerediNumberNat_one : ruzsaSzemerediNumberNat 1 = 0 := + le_zero_iff.1 ruzsaSzemerediNumberNat_le + +@[simp] lemma ruzsaSzemerediNumberNat_two : ruzsaSzemerediNumberNat 2 = 0 := + le_zero_iff.1 ruzsaSzemerediNumberNat_le + +end ruzsaSzemerediNumber + +/-! ### The Ruzsa-Szemerédi construction -/ + +section RuzsaSzemeredi +variable [Fintype α] [CommRing α] {s : Finset α} {x : α × α × α} + +/-- The triangle indices for the Ruzsa-Szemerédi construction. -/ +private def triangleIndices (s : Finset α) : Finset (α × α × α) := + (univ ×ˢ s).map + ⟨fun xa ↦ (xa.1, xa.1 + xa.2, xa.1 + 2 * xa.2), by + rintro ⟨x, a⟩ ⟨y, b⟩ h + simp only [Prod.ext_iff] at h + obtain rfl := h.1 + obtain rfl := add_right_injective _ h.2.1 + rfl⟩ + +@[simp] +private lemma mem_triangleIndices : + x ∈ triangleIndices s ↔ ∃ y, ∃ a ∈ s, (y, y + a, y + 2 * a) = x := by simp [triangleIndices] + +@[simp] +private lemma card_triangleIndices : #(triangleIndices s) = card α * #s := by + simp [triangleIndices, card_univ] + +private lemma noAccidental (hs : ThreeAPFree (s : Set α)) : + NoAccidental (triangleIndices s : Finset (α × α × α)) where + eq_or_eq_or_eq := by + simp only [mem_triangleIndices, Prod.mk.inj_iff, exists_prop, forall_exists_index, and_imp] + rintro _ _ _ _ _ _ d a ha rfl rfl rfl b' b hb rfl rfl h₁ d' c hc rfl h₂ rfl + have : a + c = b + b := by linear_combination h₁.symm - h₂.symm + obtain rfl := hs ha hb hc this + simp_all + +variable [Fact <| IsUnit (2 : α)] + +private instance : ExplicitDisjoint (triangleIndices s : Finset (α × α × α)) where + inj₀ := by + simp only [mem_triangleIndices, Prod.mk.inj_iff, exists_prop, forall_exists_index, and_imp] + rintro _ _ _ _ x a ha rfl rfl rfl y b hb rfl h₁ h₂ + linear_combination 2 * h₁.symm - h₂.symm + inj₁ := by + simp only [mem_triangleIndices, Prod.mk.inj_iff, exists_prop, forall_exists_index, and_imp] + rintro _ _ _ _ x a ha rfl rfl rfl y b hb rfl rfl h + simpa [(Fact.out (p := IsUnit (2 : α))).mul_right_inj, eq_comm] using h + inj₂ := by + simp only [mem_triangleIndices, Prod.mk.inj_iff, exists_prop, forall_exists_index, and_imp] + rintro _ _ _ _ x a ha rfl rfl rfl y b hb rfl h rfl + simpa [(Fact.out (p := IsUnit (2 : α))).mul_right_inj, eq_comm] using h + +private lemma locallyLinear (hs : ThreeAPFree (s : Set α)) : + (graph <| triangleIndices s).LocallyLinear := + haveI := noAccidental hs; TripartiteFromTriangles.locallyLinear _ + +private lemma card_edgeFinset (hs : ThreeAPFree (s : Set α)) [DecidableEq α] : + #(graph <| triangleIndices s).edgeFinset = 3 * card α * #s := by + haveI := noAccidental hs + rw [(locallyLinear hs).card_edgeFinset, card_triangles, card_triangleIndices, mul_assoc] + +end RuzsaSzemeredi + +variable (α) [Fintype α] [DecidableEq α] [CommRing α] [Fact <| IsUnit (2 : α)] + +lemma addRothNumber_le_ruzsaSzemerediNumber : + card α * addRothNumber (univ : Finset α) ≤ ruzsaSzemerediNumber (Sum α (Sum α α)) := by + obtain ⟨s, -, hscard, hs⟩ := addRothNumber_spec (univ : Finset α) + haveI := noAccidental hs + rw [← hscard, ← card_triangleIndices, ← card_triangles] + exact (locallyLinear hs).le_ruzsaSzemerediNumber + +lemma rothNumberNat_le_ruzsaSzemerediNumberNat (n : ℕ) : + (2 * n + 1) * rothNumberNat n ≤ ruzsaSzemerediNumberNat (6 * n + 3) := by + let α := Fin (2 * n + 1) + have : Nat.Coprime 2 (2 * n + 1) := by simp + haveI : Fact (IsUnit (2 : Fin (2 * n + 1))) := ⟨by simpa using (ZMod.unitOfCoprime 2 this).isUnit⟩ + calc + (2 * n + 1) * rothNumberNat n + _ = Fintype.card α * addRothNumber (Iio (n : α)) := by + rw [Fin.addRothNumber_eq_rothNumberNat le_rfl, Fintype.card_fin] + _ ≤ Fintype.card α * addRothNumber (univ : Finset α) := by + gcongr; exact subset_univ _ + _ ≤ ruzsaSzemerediNumber (Sum α (Sum α α)) := addRothNumber_le_ruzsaSzemerediNumber _ + _ = ruzsaSzemerediNumberNat (6 * n + 3) := by + simp_rw [← ruzsaSzemerediNumberNat_card, Fintype.card_sum, α, Fintype.card_fin] + ring_nf + +/-- Lower bound on the **Ruzsa-Szemerédi problem** in terms of 3AP-free sets. + +If there exists a 3AP-free subset of `[1, ..., (n - 3) / 6]` of size `m`, then there exists a graph +with `n` vertices and `(n / 3 - 2) * m` edges such that each edge belongs to exactly one triangle. +-/ +theorem rothNumberNat_le_ruzsaSzemerediNumberNat' : + ∀ n : ℕ, (n / 3 - 2 : ℝ) * rothNumberNat ((n - 3) / 6) ≤ ruzsaSzemerediNumberNat n + | 0 => by simp + | 1 => by simp + | 2 => by simp + | n + 3 => by + calc + _ ≤ (↑(2 * (n / 6) + 1) : ℝ) * rothNumberNat (n / 6) := + mul_le_mul_of_nonneg_right ?_ (Nat.cast_nonneg _) + _ ≤ (ruzsaSzemerediNumberNat (6 * (n / 6) + 3) : ℝ) := ?_ + _ ≤ _ := + Nat.cast_le.2 (ruzsaSzemerediNumberNat_mono <| add_le_add_right (Nat.mul_div_le _ _) _) + · norm_num + rw [← div_add_one (three_ne_zero' ℝ), ← le_sub_iff_add_le, div_le_iff₀ (zero_lt_three' ℝ), + add_assoc, add_sub_assoc, add_mul, mul_right_comm] + norm_num + norm_cast + rw [← mul_add_one] + exact (Nat.lt_mul_div_succ _ <| by norm_num).le + · norm_cast + exact rothNumberNat_le_ruzsaSzemerediNumberNat _ + +/-- Explicit lower bound on the **Ruzsa-Szemerédi problem**. + +There exists a graph with `n` vertices and +`(n / 3 - 2) * (n - 3) / 6 * exp (-4 * sqrt (log ((n - 3) / 6)))` edges such that each edge belongs +to exactly one triangle. -/ +theorem ruzsaSzemerediNumberNat_lower_bound (n : ℕ) : + (n / 3 - 2 : ℝ) * ↑((n - 3) / 6) * exp (-4 * sqrt (log ↑((n - 3) / 6))) ≤ + ruzsaSzemerediNumberNat n := by + rw [mul_assoc] + obtain hn | hn := le_total (n / 3 - 2 : ℝ) 0 + · exact (mul_nonpos_of_nonpos_of_nonneg hn <| by positivity).trans (Nat.cast_nonneg _) + exact + (mul_le_mul_of_nonneg_left Behrend.roth_lower_bound hn).trans + (rothNumberNat_le_ruzsaSzemerediNumberNat' _) + +open Asymptotics Filter + +/-- Asymptotic lower bound on the **Ruzsa-Szemerédi problem**. + +There exists a graph with `n` vertices and `Ω((n ^ 2 * exp (-4 * sqrt (log n))))` edges such that +each edge belongs to exactly one triangle. -/ +theorem ruzsaSzemerediNumberNat_asymptotic_lower_bound : + (fun n ↦ n ^ 2 * exp (-4 * sqrt (log n)) : ℕ → ℝ) =O[atTop] + fun n ↦ (ruzsaSzemerediNumberNat n : ℝ) := by + trans fun n ↦ (n / 3 - 2) * ↑((n - 3) / 6) * exp (-4 * sqrt (log ↑((n - 3) / 6))) + · simp_rw [sq] + refine (IsBigO.mul ?_ ?_).mul ?_ + · trans fun n ↦ n / 3 + · simp_rw [div_eq_inv_mul] + exact (isBigO_refl ..).const_mul_right (by norm_num) + refine IsLittleO.right_isBigO_sub ?_ + simpa [div_eq_inv_mul, Function.comp_def] using + .atTop_of_const_mul zero_lt_three (by simp [tendsto_natCast_atTop_atTop]) + · rw [IsBigO_def] + refine ⟨12, ?_⟩ + simp only [IsBigOWith, norm_natCast, eventually_atTop] + exact ⟨15, fun x hx ↦ by norm_cast; omega⟩ + · rw [isBigO_exp_comp_exp_comp] + refine ⟨0, ?_⟩ + simp only [neg_mul, eventually_map, Pi.sub_apply, sub_neg_eq_add, neg_add_le_iff_le_add, + add_zero, ofNat_pos, _root_.mul_le_mul_left, eventually_atTop] + refine ⟨9, fun x hx ↦ ?_⟩ + gcongr + · simp + omega + · omega + · refine .of_bound 1 ?_ + simp only [neg_mul, norm_eq_abs, norm_natCast, one_mul, eventually_atTop] + refine ⟨6, fun n hn ↦ ?_⟩ + have : (0 : ℝ) ≤ n / 3 - 2 := by rify at hn; linarith + simpa using abs_le_abs_of_nonneg (by positivity) (ruzsaSzemerediNumberNat_lower_bound n) diff --git a/Mathlib/Combinatorics/Hall/Basic.lean b/Mathlib/Combinatorics/Hall/Basic.lean index da15e7bee4a35..1cd190b29bab4 100644 --- a/Mathlib/Combinatorics/Hall/Basic.lean +++ b/Mathlib/Combinatorics/Hall/Basic.lean @@ -160,8 +160,7 @@ instance {α : Type u} {β : Type v} [DecidableEq β] (r : α → β → Prop) [∀ a : α, Fintype (Rel.image r {a})] (A : Finset α) : Fintype (Rel.image r A) := by have h : Rel.image r A = (A.biUnion fun a => (Rel.image r {a}).toFinset : Set β) := by ext - -- Porting note: added `Set.mem_toFinset` - simp [Rel.image, (Set.mem_toFinset)] + simp [Rel.image] rw [h] apply FinsetCoe.fintype @@ -185,10 +184,11 @@ theorem Fintype.all_card_le_rel_image_card_iff_exists_injective {α : Type u} { rw [← Set.toFinset_card] apply congr_arg ext b - -- Porting note: added `Set.mem_toFinset` - simp [Rel.image, (Set.mem_toFinset)] - -- Porting note: added `Set.mem_toFinset` - have h' : ∀ (f : α → β) (x), r x (f x) ↔ f x ∈ r' x := by simp [Rel.image, (Set.mem_toFinset)] + -- Porting note: added `Set.mem_toFinset` (fixed by https://github.com/leanprover/lean4/pull/6123?) + simp [r', Rel.image, (Set.mem_toFinset)] + -- Porting note: added `Set.mem_toFinset` (fixed by https://github.com/leanprover/lean4/pull/6123?) + have h' : ∀ (f : α → β) (x), r x (f x) ↔ f x ∈ r' x := by + simp [r', Rel.image, (Set.mem_toFinset)] simp only [h, h'] apply Finset.all_card_le_biUnion_card_iff_exists_injective diff --git a/Mathlib/Combinatorics/Hall/Finite.lean b/Mathlib/Combinatorics/Hall/Finite.lean index 658e17aae213d..73906569460be 100644 --- a/Mathlib/Combinatorics/Hall/Finite.lean +++ b/Mathlib/Combinatorics/Hall/Finite.lean @@ -109,7 +109,8 @@ theorem hall_hard_inductive_step_A {n : ℕ} (hn : Fintype.card ι = n + 1) have key : ∀ {x}, y ≠ f' x := by intro x h simpa [t', ← h] using hfr x - by_cases h₁ : z₁ = x <;> by_cases h₂ : z₂ = x <;> simp [h₁, h₂, hfinj.eq_iff, key, key.symm] + by_cases h₁ : z₁ = x <;> by_cases h₂ : z₂ = x <;> + simp [h₁, h₂, hfinj.eq_iff, key, key.symm] · intro z simp only [ne_eq, Set.mem_setOf_eq] split_ifs with hz diff --git a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean index 956feba606f04..25a39b29065a3 100644 --- a/Mathlib/Combinatorics/Optimization/ValuedCSP.lean +++ b/Mathlib/Combinatorics/Optimization/ValuedCSP.lean @@ -90,8 +90,7 @@ variable {m : ℕ} /-- Arity of the "output" of the fractional operation. -/ @[simp] -def FractionalOperation.size (ω : FractionalOperation D m) : ℕ := - Multiset.card.toFun ω +def FractionalOperation.size (ω : FractionalOperation D m) : ℕ := ω.card /-- Fractional operation is valid iff nonempty. -/ def FractionalOperation.IsValid (ω : FractionalOperation D m) : Prop := diff --git a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean index be6ce35efc01e..aaffbd0028f58 100644 --- a/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean +++ b/Mathlib/Combinatorics/SetFamily/AhlswedeZhang.lean @@ -103,14 +103,15 @@ variable {α β : Type*} section SemilatticeSup variable [SemilatticeSup α] [SemilatticeSup β] [BoundedOrder β] {s t : Finset α} {a : α} -private lemma sup_aux [@DecidableRel α (· ≤ ·)] : a ∈ lowerClosure s → {b ∈ s | a ≤ b}.Nonempty := +private lemma sup_aux [DecidableRel (α := α) (· ≤ ·)] : + a ∈ lowerClosure s → {b ∈ s | a ≤ b}.Nonempty := fun ⟨b, hb, hab⟩ ↦ ⟨b, mem_filter.2 ⟨hb, hab⟩⟩ private lemma lower_aux [DecidableEq α] : a ∈ lowerClosure ↑(s ∪ t) ↔ a ∈ lowerClosure s ∨ a ∈ lowerClosure t := by rw [coe_union, lowerClosure_union, LowerSet.mem_sup_iff] -variable [@DecidableRel α (· ≤ ·)] [OrderTop α] +variable [DecidableRel (α := α) (· ≤ ·)] [OrderTop α] /-- The supremum of the elements of `s` less than `a` if there are some, otherwise `⊤`. -/ def truncatedSup (s : Finset α) (a : α) : α := @@ -133,7 +134,7 @@ lemma le_truncatedSup : a ≤ truncatedSup s a := by exact h.trans <| le_sup' id <| mem_filter.2 ⟨hb, h⟩ · exact le_top -lemma map_truncatedSup [@DecidableRel β (· ≤ ·)] (e : α ≃o β) (s : Finset α) (a : α) : +lemma map_truncatedSup [DecidableRel (α := β) (· ≤ ·)] (e : α ≃o β) (s : Finset α) (a : α) : e (truncatedSup s a) = truncatedSup (s.map e.toEquiv.toEmbedding) (e a) := by have : e a ∈ lowerClosure (s.map e.toEquiv.toEmbedding : Set β) ↔ a ∈ lowerClosure s := by simp simp_rw [truncatedSup, apply_dite e, map_finset_sup', map_top, this] @@ -174,16 +175,17 @@ end SemilatticeSup section SemilatticeInf variable [SemilatticeInf α] [SemilatticeInf β] - [BoundedOrder β] [@DecidableRel β (· ≤ ·)] {s t : Finset α} {a : α} + [BoundedOrder β] [DecidableRel (α := β) (· ≤ ·)] {s t : Finset α} {a : α} -private lemma inf_aux [@DecidableRel α (· ≤ ·)]: a ∈ upperClosure s → {b ∈ s | b ≤ a}.Nonempty := +private lemma inf_aux [DecidableRel (α := α) (· ≤ ·)] : + a ∈ upperClosure s → {b ∈ s | b ≤ a}.Nonempty := fun ⟨b, hb, hab⟩ ↦ ⟨b, mem_filter.2 ⟨hb, hab⟩⟩ private lemma upper_aux [DecidableEq α] : a ∈ upperClosure ↑(s ∪ t) ↔ a ∈ upperClosure s ∨ a ∈ upperClosure t := by rw [coe_union, upperClosure_union, UpperSet.mem_inf_iff] -variable [@DecidableRel α (· ≤ ·)] [BoundedOrder α] +variable [DecidableRel (α := α) (· ≤ ·)] [BoundedOrder α] /-- The infimum of the elements of `s` less than `a` if there are some, otherwise `⊥`. -/ def truncatedInf (s : Finset α) (a : α) : α := @@ -256,7 +258,7 @@ private lemma infs_aux : a ∈ lowerClosure ↑(s ⊼ t) ↔ a ∈ lowerClosure private lemma sups_aux : a ∈ upperClosure ↑(s ⊻ t) ↔ a ∈ upperClosure s ∧ a ∈ upperClosure t := by rw [coe_sups, upperClosure_sups, UpperSet.mem_sup_iff] -variable [@DecidableRel α (· ≤ ·)] [BoundedOrder α] +variable [DecidableRel (α := α) (· ≤ ·)] [BoundedOrder α] lemma truncatedSup_infs (hs : a ∈ lowerClosure s) (ht : a ∈ lowerClosure t) : truncatedSup (s ⊼ t) a = truncatedSup s a ⊓ truncatedSup t a := by @@ -283,7 +285,7 @@ lemma truncatedInf_sups_of_not_mem (ha : a ∉ upperClosure s ⊔ upperClosure t end DistribLattice section BooleanAlgebra -variable [BooleanAlgebra α] [@DecidableRel α (· ≤ ·)] +variable [BooleanAlgebra α] [DecidableRel (α := α) (· ≤ ·)] @[simp] lemma compl_truncatedSup (s : Finset α) (a : α) : (truncatedSup s a)ᶜ = truncatedInf sᶜˢ aᶜ := map_truncatedSup (OrderIso.compl α) _ _ diff --git a/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean index edfdf5d218350..d3655a022cb05 100644 --- a/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean +++ b/Mathlib/Combinatorics/SetFamily/KruskalKatona.lean @@ -143,7 +143,8 @@ lemma toColex_compress_lt_toColex {hU : U.Nonempty} {hV : V.Nonempty} (h : max' private def UsefulCompression (U V : Finset α) : Prop := Disjoint U V ∧ #U = #V ∧ ∃ (HU : U.Nonempty) (HV : V.Nonempty), max' U HU < max' V HV -private instance UsefulCompression.instDecidableRel : @DecidableRel (Finset α) UsefulCompression := +private instance UsefulCompression.instDecidableRel : + DecidableRel (α := Finset α) UsefulCompression := fun _ _ ↦ inferInstanceAs (Decidable (_ ∧ _)) /-- Applying a good compression will decrease measure, keep cardinality, keep sizes and decrease diff --git a/Mathlib/Combinatorics/SetFamily/Shatter.lean b/Mathlib/Combinatorics/SetFamily/Shatter.lean index 27a76906f15d6..a9fb7d184ba69 100644 --- a/Mathlib/Combinatorics/SetFamily/Shatter.lean +++ b/Mathlib/Combinatorics/SetFamily/Shatter.lean @@ -137,7 +137,7 @@ lemma card_le_card_shatterer (𝒜 : Finset (Finset α)) : #𝒜 ≤ #𝒜.shatt rw [mem_memberSubfamily] at hv rw [← singleton_subset_iff (a := a), ← hsv] at hv exact hv.2 inter_subset_right - · refine forall_image.2 fun s hs ↦ mem_shatterer.2 fun t ht ↦ ?_ + · refine forall_mem_image.2 fun s hs ↦ mem_shatterer.2 fun t ht ↦ ?_ simp only [mem_inter, mem_shatterer] at hs rw [subset_insert_iff] at ht by_cases ha : a ∈ t diff --git a/Mathlib/Combinatorics/SimpleGraph/Basic.lean b/Mathlib/Combinatorics/SimpleGraph/Basic.lean index 1da6a51b3e613..fbf6473d0fddf 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Basic.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Basic.lean @@ -603,7 +603,7 @@ theorem fromEdgeSet_sdiff (s t : Set (Sym2 V)) : ext v w constructor <;> simp +contextual -@[mono] +@[gcongr, mono] theorem fromEdgeSet_mono {s t : Set (Sym2 V)} (h : s ⊆ t) : fromEdgeSet s ≤ fromEdgeSet t := by rintro v w simp +contextual only [fromEdgeSet_adj, Ne, not_false_iff, diff --git a/Mathlib/Combinatorics/SimpleGraph/Clique.lean b/Mathlib/Combinatorics/SimpleGraph/Clique.lean index dd588e24a5611..ea2c7d7ec4dbc 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Clique.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Clique.lean @@ -493,7 +493,7 @@ theorem cliqueSet_eq_empty_iff : G.cliqueSet n = ∅ ↔ G.CliqueFree n := by protected alias ⟨_, CliqueFree.cliqueSet⟩ := cliqueSet_eq_empty_iff -@[mono] +@[gcongr, mono] theorem cliqueSet_mono (h : G ≤ H) : G.cliqueSet n ⊆ H.cliqueSet n := fun _ ↦ IsNClique.mono h @@ -636,7 +636,7 @@ theorem card_cliqueFinset_le : #(G.cliqueFinset n) ≤ (card α).choose n := by variable [DecidableRel H.Adj] -@[mono] +@[gcongr, mono] theorem cliqueFinset_mono (h : G ≤ H) : G.cliqueFinset n ⊆ H.cliqueFinset n := monotone_filter_right _ fun _ ↦ IsNClique.mono h diff --git a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean index 171bc81387364..559e58c4930b6 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Connectivity/WalkCounting.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.BigOperators.Ring.Nat import Mathlib.Combinatorics.SimpleGraph.Path import Mathlib.Combinatorics.SimpleGraph.Subgraph import Mathlib.SetTheory.Cardinal.Finite +import Mathlib.Data.Set.Finite.Lattice /-! # Counting walks of a given length diff --git a/Mathlib/Combinatorics/SimpleGraph/Matching.lean b/Mathlib/Combinatorics/SimpleGraph/Matching.lean index d52240d416332..1e27af2e43ad5 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Matching.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Matching.lean @@ -27,6 +27,14 @@ one edge, and the edges of the subgraph represent the paired vertices. * `SimpleGraph.Subgraph.IsPerfectMatching` defines when a subgraph `M` of a simple graph is a perfect matching, denoted `M.IsPerfectMatching`. +* `SimpleGraph.IsMatchingFree` means that a graph `G` has no perfect matchings. + +* `SimpleGraph.IsCycles` means that a graph consists of cycles (including cycles of length 0, + also known as isolated vertices) + +* `SimpleGraph.IsAlternating` means that edges in a graph `G` are alternatingly + included and not included in some other graph `G'` + ## TODO * Define an `other` function and prove useful results about it (https://leanprover.zulipchat.com/#narrow/stream/252551-graph-theory/topic/matchings/near/266205863) @@ -309,4 +317,81 @@ lemma exists_maximal_isMatchingFree [Finite V] (h : G.IsMatchingFree) : obtain ⟨Gmax, hGmax⟩ := Finite.exists_le_maximal h exact ⟨Gmax, ⟨hGmax.1, ⟨hGmax.2.prop, fun _ h' ↦ hGmax.2.not_prop_of_gt h'⟩⟩⟩ +/-- A graph `G` consists of a set of cycles, if each vertex is either isolated or connected to +exactly two vertices. This is used to create new matchings by taking the `symmDiff` with cycles. +The definition of `symmDiff` that makes sense is the one for `SimpleGraph`. The `symmDiff` +for `SimpleGraph.Subgraph` deriving from the lattice structure also affects the vertices included, +which we do not want in this case. This is why this property is defined for `SimpleGraph`, rather +than `SimpleGraph.Subgraph`. +-/ +def IsCycles (G : SimpleGraph V) := ∀ ⦃v⦄, (G.neighborSet v).Nonempty → (G.neighborSet v).ncard = 2 + +/-- +Given a vertex with one edge in a graph of cycles this gives the other edge incident +to the same vertex. +-/ +lemma IsCycles.other_adj_of_adj (h : G.IsCycles) (hadj : G.Adj v w) : + ∃ w', w ≠ w' ∧ G.Adj v w' := by + simp_rw [← SimpleGraph.mem_neighborSet] at hadj ⊢ + have := h ⟨w, hadj⟩ + obtain ⟨w', hww'⟩ := (G.neighborSet v).exists_ne_of_one_lt_ncard (by omega) w + exact ⟨w', ⟨hww'.2.symm, hww'.1⟩⟩ + +open scoped symmDiff + +lemma Subgraph.IsPerfectMatching.symmDiff_spanningCoe_IsCycles + {M : Subgraph G} {M' : Subgraph G'} (hM : M.IsPerfectMatching) + (hM' : M'.IsPerfectMatching) : (M.spanningCoe ∆ M'.spanningCoe).IsCycles := by + intro v + obtain ⟨w, hw⟩ := hM.1 (hM.2 v) + obtain ⟨w', hw'⟩ := hM'.1 (hM'.2 v) + simp only [symmDiff_def, Set.ncard_eq_two, ne_eq, imp_iff_not_or, Set.not_nonempty_iff_eq_empty, + Set.eq_empty_iff_forall_not_mem, SimpleGraph.mem_neighborSet, SimpleGraph.sup_adj, sdiff_adj, + spanningCoe_adj, not_or, not_and, not_not] + by_cases hww' : w = w' + · simp_all [← imp_iff_not_or, hww'] + · right + use w, w' + aesop + +/-- +A graph `G` is alternating with respect to some other graph `G'`, if exactly every other edge in +`G` is in `G'`. Note that the degree of each vertex needs to be at most 2 for this to be +possible. This property is used to create new matchings using `symmDiff`. +The definition of `symmDiff` that makes sense is the one for `SimpleGraph`. The `symmDiff` +for `SimpleGraph.Subgraph` deriving from the lattice structure also affects the vertices included, +which we do not want in this case. This is why this property, just like `IsCycles`, is defined +for `SimpleGraph` rather than `SimpleGraph.Subgraph`. +-/ +def IsAlternating (G G' : SimpleGraph V) := + ∀ ⦃v w w': V⦄, w ≠ w' → G.Adj v w → G.Adj v w' → (G'.Adj v w ↔ ¬ G'.Adj v w') + +lemma IsPerfectMatching.symmDiff_spanningCoe_of_isAlternating {M : Subgraph G} + (hM : M.IsPerfectMatching) (hG' : G'.IsAlternating M.spanningCoe) (hG'cyc : G'.IsCycles) : + (SimpleGraph.toSubgraph (M.spanningCoe ∆ G') + (by rfl)).IsPerfectMatching := by + rw [Subgraph.isPerfectMatching_iff] + intro v + simp only [toSubgraph_adj, symmDiff_def, sup_adj, sdiff_adj, Subgraph.spanningCoe_adj] + obtain ⟨w, hw⟩ := hM.1 (hM.2 v) + by_cases h : G'.Adj v w + · obtain ⟨w', hw'⟩ := hG'cyc.other_adj_of_adj h + have hmadj : M.Adj v w ↔ ¬M.Adj v w' := by simpa using hG' hw'.1 h hw'.2 + use w' + simp only [hmadj.mp hw.1, hw'.2, not_true_eq_false, and_self, not_false_eq_true, or_true, + true_and] + rintro y (hl | hr) + · aesop + · obtain ⟨w'', hw''⟩ := hG'cyc.other_adj_of_adj hr.1 + by_contra! hc + simp_all only [show M.Adj v y ↔ ¬M.Adj v w' from by simpa using hG' hc hr.1 hw'.2, + not_false_eq_true, ne_eq, iff_true, not_true_eq_false, and_false] + · use w + simp only [hw.1, h, not_false_eq_true, and_self, not_true_eq_false, or_false, true_and] + rintro y (hl | hr) + · exact hw.2 _ hl.1 + · have ⟨w', hw'⟩ := hG'cyc.other_adj_of_adj hr.1 + simp_all only [show M.Adj v y ↔ ¬M.Adj v w' from by simpa using hG' hw'.1 hr.1 hw'.2, not_not, + ne_eq, and_false] + end SimpleGraph diff --git a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean index 3a54a207a63cd..3ee260f7663ee 100644 --- a/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean +++ b/Mathlib/Combinatorics/SimpleGraph/Subgraph.lean @@ -1077,11 +1077,11 @@ theorem induce_mono (hg : G' ≤ G'') (hs : s ⊆ s') : G'.induce s ≤ G''.indu intro v w hv hw ha exact ⟨hs hv, hs hw, hg.2 ha⟩ -@[mono] +@[gcongr, mono] theorem induce_mono_left (hg : G' ≤ G'') : G'.induce s ≤ G''.induce s := induce_mono hg subset_rfl -@[mono] +@[gcongr, mono] theorem induce_mono_right (hs : s ⊆ s') : G'.induce s ≤ G'.induce s' := induce_mono le_rfl hs @@ -1159,12 +1159,12 @@ theorem deleteVerts_empty : G'.deleteVerts ∅ = G' := by theorem deleteVerts_le : G'.deleteVerts s ≤ G' := by constructor <;> simp [Set.diff_subset] -@[mono] +@[gcongr, mono] theorem deleteVerts_mono {G' G'' : G.Subgraph} (h : G' ≤ G'') : G'.deleteVerts s ≤ G''.deleteVerts s := induce_mono h (Set.diff_subset_diff_left h.1) -@[mono] +@[gcongr, mono] theorem deleteVerts_anti {s s' : Set V} (h : s ⊆ s') : G'.deleteVerts s' ≤ G'.deleteVerts s := induce_mono (le_refl _) (Set.diff_subset_diff_right h) diff --git a/Mathlib/Combinatorics/Young/SemistandardTableau.lean b/Mathlib/Combinatorics/Young/SemistandardTableau.lean index fac50829baf05..52168fe27c5c2 100644 --- a/Mathlib/Combinatorics/Young/SemistandardTableau.lean +++ b/Mathlib/Combinatorics/Young/SemistandardTableau.lean @@ -29,8 +29,8 @@ for all pairs `(i, j) ∉ μ` and to satisfy the row-weak and column-strict cond - `SemistandardYoungTableau (μ : YoungDiagram)`: semistandard Young tableaux of shape `μ`. There is a `coe` instance such that `T i j` is value of the `(i, j)` entry of the semistandard Young tableau `T`. -- `Ssyt.highestWeight (μ : YoungDiagram)`: the semistandard Young tableau whose `i`th row - consists entirely of `i`s, for each `i`. +- `SemistandardYoungTableau.highestWeight (μ : YoungDiagram)`: the semistandard Young tableau whose + `i`th row consists entirely of `i`s, for each `i`. ## Tags diff --git a/Mathlib/Computability/Ackermann.lean b/Mathlib/Computability/Ackermann.lean index ace0d47e3ed95..92b4e6f1c3a1a 100644 --- a/Mathlib/Computability/Ackermann.lean +++ b/Mathlib/Computability/Ackermann.lean @@ -235,7 +235,7 @@ private theorem sq_le_two_pow_add_one_minus_three (n : ℕ) : n ^ 2 ≤ 2 ^ (n + norm_num apply succ_le_of_lt rw [Nat.pow_succ, mul_comm _ 2, mul_lt_mul_left (zero_lt_two' ℕ)] - apply lt_two_pow + exact Nat.lt_two_pow_self · rw [Nat.pow_succ, Nat.pow_succ] linarith [one_le_pow k 2 zero_lt_two] diff --git a/Mathlib/Computability/Halting.lean b/Mathlib/Computability/Halting.lean index 0bce012c8ecc0..7437dbc1b31ac 100644 --- a/Mathlib/Computability/Halting.lean +++ b/Mathlib/Computability/Halting.lean @@ -267,11 +267,12 @@ namespace Nat open Vector Part /-- A simplified basis for `Partrec`. -/ -inductive Partrec' : ∀ {n}, (Vector ℕ n →. ℕ) → Prop +inductive Partrec' : ∀ {n}, (Mathlib.Vector ℕ n →. ℕ) → Prop | prim {n f} : @Primrec' n f → @Partrec' n f - | comp {m n f} (g : Fin n → Vector ℕ m →. ℕ) : - Partrec' f → (∀ i, Partrec' (g i)) → Partrec' fun v => (Vector.mOfFn fun i => g i v) >>= f - | rfind {n} {f : Vector ℕ (n + 1) → ℕ} : + | comp {m n f} (g : Fin n → Mathlib.Vector ℕ m →. ℕ) : + Partrec' f → (∀ i, Partrec' (g i)) → + Partrec' fun v => (Mathlib.Vector.mOfFn fun i => g i v) >>= f + | rfind {n} {f : Mathlib.Vector ℕ (n + 1) → ℕ} : @Partrec' (n + 1) f → Partrec' fun v => rfind fun n => some (f (n ::ᵥ v) = 0) end Nat @@ -293,10 +294,11 @@ theorem to_part {n f} (pf : @Partrec' n f) : _root_.Partrec f := by this).to₂.partrec₂ exact _root_.Partrec.rfind this -theorem of_eq {n} {f g : Vector ℕ n →. ℕ} (hf : Partrec' f) (H : ∀ i, f i = g i) : Partrec' g := +theorem of_eq {n} {f g : Mathlib.Vector ℕ n →. ℕ} (hf : Partrec' f) (H : ∀ i, f i = g i) : + Partrec' g := (funext H : f = g) ▸ hf -theorem of_prim {n} {f : Vector ℕ n → ℕ} (hf : Primrec f) : @Partrec' n f := +theorem of_prim {n} {f : Mathlib.Vector ℕ n → ℕ} (hf : Primrec f) : @Partrec' n f := prim (Nat.Primrec'.of_prim hf) theorem head {n : ℕ} : @Partrec' n.succ (@head ℕ n) := @@ -313,21 +315,21 @@ protected theorem bind {n f g} (hf : @Partrec' n f) (hg : @Partrec' (n + 1) g) : exact prim (Nat.Primrec'.get _)).of_eq fun v => by simp [mOfFn, Part.bind_assoc, pure] -protected theorem map {n f} {g : Vector ℕ (n + 1) → ℕ} (hf : @Partrec' n f) +protected theorem map {n f} {g : Mathlib.Vector ℕ (n + 1) → ℕ} (hf : @Partrec' n f) (hg : @Partrec' (n + 1) g) : @Partrec' n fun v => (f v).map fun a => g (a ::ᵥ v) := by simpa [(Part.bind_some_eq_map _ _).symm] using hf.bind hg /-- Analogous to `Nat.Partrec'` for `ℕ`-valued functions, a predicate for partial recursive vector-valued functions. -/ -def Vec {n m} (f : Vector ℕ n → Vector ℕ m) := +def Vec {n m} (f : Mathlib.Vector ℕ n → Mathlib.Vector ℕ m) := ∀ i, Partrec' fun v => (f v).get i nonrec theorem Vec.prim {n m f} (hf : @Nat.Primrec'.Vec n m f) : Vec f := fun i => prim <| hf i protected theorem nil {n} : @Vec n 0 fun _ => nil := fun i => i.elim0 -protected theorem cons {n m} {f : Vector ℕ n → ℕ} {g} (hf : @Partrec' n f) (hg : @Vec n m g) : - Vec fun v => f v ::ᵥ g v := fun i => +protected theorem cons {n m} {f : Mathlib.Vector ℕ n → ℕ} {g} (hf : @Partrec' n f) + (hg : @Vec n m g) : Vec fun v => f v ::ᵥ g v := fun i => Fin.cases (by simpa using hf) (fun i => by simp only [hg i, get_cons_succ]) i theorem idv {n} : @Vec n n id := @@ -336,11 +338,11 @@ theorem idv {n} : @Vec n n id := theorem comp' {n m f g} (hf : @Partrec' m f) (hg : @Vec n m g) : Partrec' fun v => f (g v) := (hf.comp _ hg).of_eq fun v => by simp -theorem comp₁ {n} (f : ℕ →. ℕ) {g : Vector ℕ n → ℕ} (hf : @Partrec' 1 fun v => f v.head) +theorem comp₁ {n} (f : ℕ →. ℕ) {g : Mathlib.Vector ℕ n → ℕ} (hf : @Partrec' 1 fun v => f v.head) (hg : @Partrec' n g) : @Partrec' n fun v => f (g v) := by simpa using hf.comp' (Partrec'.cons hg Partrec'.nil) -theorem rfindOpt {n} {f : Vector ℕ (n + 1) → ℕ} (hf : @Partrec' (n + 1) f) : +theorem rfindOpt {n} {f : Mathlib.Vector ℕ (n + 1) → ℕ} (hf : @Partrec' (n + 1) f) : @Partrec' n fun v => Nat.rfindOpt fun a => ofNat (Option ℕ) (f (a ::ᵥ v)) := ((rfind <| (of_prim (Primrec.nat_sub.comp (_root_.Primrec.const 1) Primrec.vector_head)).comp₁ @@ -367,7 +369,7 @@ open Nat.Partrec.Code theorem of_part : ∀ {n f}, _root_.Partrec f → @Partrec' n f := @(suffices ∀ f, Nat.Partrec f → @Partrec' 1 fun v => f v.head from fun {n f} hf => by let g := fun n₁ => - (Part.ofOption (decode (α := Vector ℕ n) n₁)).bind (fun a => Part.map encode (f a)) + (Part.ofOption (decode (α := Mathlib.Vector ℕ n) n₁)).bind (fun a => Part.map encode (f a)) exact (comp₁ g (this g hf) (prim Nat.Primrec'.encode)).of_eq fun i => by dsimp only [g]; simp [encodek, Part.map_id'] diff --git a/Mathlib/Computability/Partrec.lean b/Mathlib/Computability/Partrec.lean index 700990868e922..3ad33d20e77c5 100644 --- a/Mathlib/Computability/Partrec.lean +++ b/Mathlib/Computability/Partrec.lean @@ -200,7 +200,7 @@ theorem ppred : Partrec fun n => ppred n := eq_none_iff.2 fun a ⟨⟨m, h, _⟩, _⟩ => by 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, + simp only [mem_rfind, not_true, IsEmpty.forall_iff, decide_true, mem_some_iff, false_eq_decide_iff, true_and] intro m h simp [ne_of_gt h] @@ -314,25 +314,25 @@ theorem list_concat : Computable₂ fun l (a : α) => l ++ [a] := theorem list_length : Computable (@List.length α) := Primrec.list_length.to_comp -theorem vector_cons {n} : Computable₂ (@Vector.cons α n) := +theorem vector_cons {n} : Computable₂ (@Mathlib.Vector.cons α n) := Primrec.vector_cons.to_comp -theorem vector_toList {n} : Computable (@Vector.toList α n) := +theorem vector_toList {n} : Computable (@Mathlib.Vector.toList α n) := Primrec.vector_toList.to_comp -theorem vector_length {n} : Computable (@Vector.length α n) := +theorem vector_length {n} : Computable (@Mathlib.Vector.length α n) := Primrec.vector_length.to_comp -theorem vector_head {n} : Computable (@Vector.head α n) := +theorem vector_head {n} : Computable (@Mathlib.Vector.head α n) := Primrec.vector_head.to_comp -theorem vector_tail {n} : Computable (@Vector.tail α n) := +theorem vector_tail {n} : Computable (@Mathlib.Vector.tail α n) := Primrec.vector_tail.to_comp -theorem vector_get {n} : Computable₂ (@Vector.get α n) := +theorem vector_get {n} : Computable₂ (@Mathlib.Vector.get α n) := Primrec.vector_get.to_comp -theorem vector_ofFn' {n} : Computable (@Vector.ofFn α n) := +theorem vector_ofFn' {n} : Computable (@Mathlib.Vector.ofFn α n) := Primrec.vector_ofFn'.to_comp theorem fin_app {n} : Computable₂ (@id (Fin n → σ)) := @@ -523,7 +523,8 @@ end Partrec @[simp] theorem Vector.mOfFn_part_some {α n} : - ∀ f : Fin n → α, (Vector.mOfFn fun i => Part.some (f i)) = Part.some (Vector.ofFn f) := + ∀ f : Fin n → α, + (Mathlib.Vector.mOfFn fun i => Part.some (f i)) = Part.some (Mathlib.Vector.ofFn f) := Vector.mOfFn_pure namespace Computable @@ -642,7 +643,7 @@ theorem list_ofFn : exact list_cons.comp (hf 0) (list_ofFn fun i => hf i.succ) theorem vector_ofFn {n} {f : Fin n → α → σ} (hf : ∀ i, Computable (f i)) : - Computable fun a => Vector.ofFn fun i => f i a := + Computable fun a => Mathlib.Vector.ofFn fun i => f i a := (Partrec.vector_mOfFn hf).of_eq fun a => by simp end Computable diff --git a/Mathlib/Computability/PartrecCode.lean b/Mathlib/Computability/PartrecCode.lean index df168bf2c9f6d..02daf224ca8e5 100644 --- a/Mathlib/Computability/PartrecCode.lean +++ b/Mathlib/Computability/PartrecCode.lean @@ -902,7 +902,7 @@ private theorem evaln_map (k c n) : ((List.range k)[n]?.bind fun a ↦ evaln k c a) = evaln k c n := by by_cases kn : n < k · simp [List.getElem?_range kn] - · rw [List.getElem?_len_le] + · rw [List.getElem?_eq_none] · cases e : evaln k c n · rfl exact kn.elim (evaln_bound e) diff --git a/Mathlib/Computability/Primrec.lean b/Mathlib/Computability/Primrec.lean index f7492a1e781aa..76aceca0eb52f 100644 --- a/Mathlib/Computability/Primrec.lean +++ b/Mathlib/Computability/Primrec.lean @@ -1101,7 +1101,7 @@ def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodab instance fin {n} : Primcodable (Fin n) := @ofEquiv _ _ (subtype <| nat_lt.comp .id (const n)) Fin.equivSubtype -instance vector {n} : Primcodable (Vector α n) := +instance vector {n} : Primcodable (Mathlib.Vector α n) := subtype ((@Primrec.eq ℕ _ _).comp list_length (const _)) instance finArrow {n} : Primcodable (Fin n → α) := @@ -1184,25 +1184,26 @@ theorem fin_val {n} : Primrec (fun (i : Fin n) => (i : ℕ)) := theorem fin_succ {n} : Primrec (@Fin.succ n) := fin_val_iff.1 <| by simp [succ.comp fin_val] -theorem vector_toList {n} : Primrec (@Vector.toList α n) := +theorem vector_toList {n} : Primrec (@Mathlib.Vector.toList α n) := subtype_val -theorem vector_toList_iff {n} {f : α → Vector β n} : (Primrec fun a => (f a).toList) ↔ Primrec f := +theorem vector_toList_iff {n} {f : α → Mathlib.Vector β n} : + (Primrec fun a => (f a).toList) ↔ Primrec f := subtype_val_iff -theorem vector_cons {n} : Primrec₂ (@Vector.cons α n) := +theorem vector_cons {n} : Primrec₂ (@Mathlib.Vector.cons α n) := vector_toList_iff.1 <| by simpa using list_cons.comp fst (vector_toList_iff.2 snd) -theorem vector_length {n} : Primrec (@Vector.length α n) := +theorem vector_length {n} : Primrec (@Mathlib.Vector.length α n) := const _ -theorem vector_head {n} : Primrec (@Vector.head α n) := +theorem vector_head {n} : Primrec (@Mathlib.Vector.head α n) := option_some_iff.1 <| (list_head?.comp vector_toList).of_eq fun ⟨_ :: _, _⟩ => rfl -theorem vector_tail {n} : Primrec (@Vector.tail α n) := +theorem vector_tail {n} : Primrec (@Mathlib.Vector.tail α n) := vector_toList_iff.1 <| (list_tail.comp vector_toList).of_eq fun ⟨l, h⟩ => by cases l <;> rfl -theorem vector_get {n} : Primrec₂ (@Vector.get α n) := +theorem vector_get {n} : Primrec₂ (@Mathlib.Vector.get α n) := option_some_iff.1 <| (list_get?.comp (vector_toList.comp fst) (fin_val.comp snd)).of_eq fun a => by rw [Vector.get_eq_get, ← List.get?_eq_get] @@ -1215,13 +1216,13 @@ theorem list_ofFn : simpa [List.ofFn_succ] using list_cons.comp (hf 0) (list_ofFn fun i => hf i.succ) theorem vector_ofFn {n} {f : Fin n → α → σ} (hf : ∀ i, Primrec (f i)) : - Primrec fun a => Vector.ofFn fun i => f i a := + Primrec fun a => Mathlib.Vector.ofFn fun i => f i a := vector_toList_iff.1 <| by simp [list_ofFn hf] -theorem vector_get' {n} : Primrec (@Vector.get α n) := +theorem vector_get' {n} : Primrec (@Mathlib.Vector.get α n) := of_equiv_symm -theorem vector_ofFn' {n} : Primrec (@Vector.ofFn α n) := +theorem vector_ofFn' {n} : Primrec (@Mathlib.Vector.ofFn α n) := of_equiv theorem fin_app {n} : Primrec₂ (@id (Fin n → σ)) := @@ -1248,16 +1249,16 @@ open Mathlib.Vector work with n-ary functions on ℕ instead of unary functions. We prove that this is equivalent to the regular notion in `to_prim` and `of_prim`. -/ -inductive Primrec' : ∀ {n}, (Vector ℕ n → ℕ) → Prop +inductive Primrec' : ∀ {n}, (Mathlib.Vector ℕ n → ℕ) → Prop | zero : @Primrec' 0 fun _ => 0 | succ : @Primrec' 1 fun v => succ v.head | get {n} (i : Fin n) : Primrec' fun v => v.get i - | comp {m n f} (g : Fin n → Vector ℕ m → ℕ) : - Primrec' f → (∀ i, Primrec' (g i)) → Primrec' fun a => f (ofFn fun i => g i a) + | comp {m n f} (g : Fin n → Mathlib.Vector ℕ m → ℕ) : + Primrec' f → (∀ i, Primrec' (g i)) → Primrec' fun a => f (Mathlib.Vector.ofFn fun i => g i a) | prec {n f g} : @Primrec' n f → @Primrec' (n + 2) g → - Primrec' fun v : Vector ℕ (n + 1) => + Primrec' fun v : Mathlib.Vector ℕ (n + 1) => v.head.rec (f v.tail) fun y IH => g (y ::ᵥ IH ::ᵥ v.tail) end Nat @@ -1280,7 +1281,8 @@ theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by Primrec.vector_cons.comp (Primrec.snd.comp .snd) <| (@Primrec.vector_tail _ _ (n + 1)).comp .fst).to₂ -theorem of_eq {n} {f g : Vector ℕ n → ℕ} (hf : Primrec' f) (H : ∀ i, f i = g i) : Primrec' g := +theorem of_eq {n} {f g : Mathlib.Vector ℕ n → ℕ} (hf : Primrec' f) (H : ∀ i, f i = g i) : + Primrec' g := (funext H : f = g) ▸ hf theorem const {n} : ∀ m, @Primrec' n fun _ => m @@ -1295,7 +1297,7 @@ theorem tail {n f} (hf : @Primrec' n f) : @Primrec' n.succ fun v => f v.tail := rw [← ofFn_get v.tail]; congr; funext i; simp /-- A function from vectors to vectors is primitive recursive when all of its projections are. -/ -def Vec {n m} (f : Vector ℕ n → Vector ℕ m) : Prop := +def Vec {n m} (f : Mathlib.Vector ℕ n → Mathlib.Vector ℕ m) : Prop := ∀ i, Primrec' fun v => (f v).get i protected theorem nil {n} : @Vec n 0 fun _ => nil := fun i => i.elim0 @@ -1390,7 +1392,7 @@ theorem unpair₂ {n f} (hf : @Primrec' n f) : @Primrec' n fun v => (f v).unpair theorem of_prim {n f} : Primrec f → @Primrec' n f := suffices ∀ f, Nat.Primrec f → @Primrec' 1 fun v => f v.head from fun hf => (pred.comp₁ _ <| - (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Vector ℕ n) _ m).map f) + (this _ hf).comp₁ (fun m => Encodable.encode <| (@decode (Mathlib.Vector ℕ n) _ m).map f) Primrec'.encode).of_eq fun i => by simp [encodek] fun f hf => by diff --git a/Mathlib/Computability/TMToPartrec.lean b/Mathlib/Computability/TMToPartrec.lean index 5ef3c02a32d1c..effb93335081f 100644 --- a/Mathlib/Computability/TMToPartrec.lean +++ b/Mathlib/Computability/TMToPartrec.lean @@ -239,12 +239,14 @@ def prec (f g : Code) : Code := attribute [-simp] Part.bind_eq_bind Part.map_eq_map Part.pure_eq_some -theorem exists_code.comp {m n} {f : Vector ℕ n →. ℕ} {g : Fin n → Vector ℕ m →. ℕ} - (hf : ∃ c : Code, ∀ v : Vector ℕ n, c.eval v.1 = pure <$> f v) - (hg : ∀ i, ∃ c : Code, ∀ v : Vector ℕ m, c.eval v.1 = pure <$> g i v) : - ∃ c : Code, ∀ v : Vector ℕ m, c.eval v.1 = pure <$> ((Vector.mOfFn fun i => g i v) >>= f) := by +theorem exists_code.comp {m n} {f : Mathlib.Vector ℕ n →. ℕ} {g : Fin n → Mathlib.Vector ℕ m →. ℕ} + (hf : ∃ c : Code, ∀ v : Mathlib.Vector ℕ n, c.eval v.1 = pure <$> f v) + (hg : ∀ i, ∃ c : Code, ∀ v : Mathlib.Vector ℕ m, c.eval v.1 = pure <$> g i v) : + ∃ c : Code, ∀ v : Mathlib.Vector ℕ m, + c.eval v.1 = pure <$> ((Mathlib.Vector.mOfFn fun i => g i v) >>= f) := by rsuffices ⟨cg, hg⟩ : - ∃ c : Code, ∀ v : Vector ℕ m, c.eval v.1 = Subtype.val <$> Vector.mOfFn fun i => g i v + ∃ c : Code, ∀ v : Mathlib.Vector ℕ m, + c.eval v.1 = Subtype.val <$> Mathlib.Vector.mOfFn fun i => g i v · obtain ⟨cf, hf⟩ := hf exact ⟨cf.comp cg, fun v => by @@ -259,8 +261,8 @@ theorem exists_code.comp {m n} {f : Vector ℕ n →. ℕ} {g : Fin n → Vector simp [Vector.mOfFn, hg₁, map_bind, seq_bind_eq, bind_assoc, (· ∘ ·), hl] rfl⟩ -theorem exists_code {n} {f : Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : - ∃ c : Code, ∀ v : Vector ℕ n, c.eval v.1 = pure <$> f v := by +theorem exists_code {n} {f : Mathlib.Vector ℕ n →. ℕ} (hf : Nat.Partrec' f) : + ∃ c : Code, ∀ v : Mathlib.Vector ℕ n, c.eval v.1 = pure <$> f v := by induction hf with | prim hf => induction hf with @@ -1402,8 +1404,8 @@ theorem succ_ok {q s n} {c d : List Γ'} : simp only [TM2.step, trList, trNat.eq_1, Nat.cast_succ, Num.add_one] cases' (n : Num) with a · refine TransGen.head rfl ?_ - simp only [Option.mem_def, TM2.stepAux, elim_main, decide_False, elim_update_main, ne_eq, - Function.update_noteq, elim_rev, elim_update_rev, decide_True, Function.update_same, + simp only [Option.mem_def, TM2.stepAux, elim_main, decide_false, elim_update_main, ne_eq, + Function.update_noteq, elim_rev, elim_update_rev, decide_true, Function.update_same, cond_true, cond_false] convert unrev_ok using 1 simp only [elim_update_rev, elim_rev, elim_main, List.reverseAux_nil, elim_update_main] @@ -1446,7 +1448,7 @@ theorem pred_ok (q₁ q₂ s v) (c d : List Γ') : ∃ s', · simp only [trPosNum, List.singleton_append, List.nil_append] refine TransGen.head rfl ?_ simp only [Option.mem_def, TM2.stepAux, elim_main, List.head?_cons, Option.some.injEq, - decide_False, List.tail_cons, elim_update_main, ne_eq, Function.update_noteq, elim_rev, + decide_false, List.tail_cons, elim_update_main, ne_eq, Function.update_noteq, elim_rev, elim_update_rev, natEnd, Function.update_same, cond_true, cond_false] convert unrev_ok using 2 simp diff --git a/Mathlib/Computability/TuringMachine.lean b/Mathlib/Computability/TuringMachine.lean index 4e3298c29a939..0f1145c0c16ee 100644 --- a/Mathlib/Computability/TuringMachine.lean +++ b/Mathlib/Computability/TuringMachine.lean @@ -1443,7 +1443,7 @@ open TM1 variable {Γ : Type*} theorem exists_enc_dec [Inhabited Γ] [Finite Γ] : - ∃ (n : ℕ) (enc : Γ → Vector Bool n) (dec : Vector Bool n → Γ), + ∃ (n : ℕ) (enc : Γ → Mathlib.Vector Bool n) (dec : Mathlib.Vector Bool n → Γ), enc default = Vector.replicate n false ∧ ∀ a, dec (enc a) = a := by rcases Finite.exists_equiv_fin Γ with ⟨n, ⟨e⟩⟩ letI : DecidableEq Γ := e.decidableEq @@ -1475,13 +1475,13 @@ local notation "Stmt'₁" => Stmt Bool Λ'₁ σ local notation "Cfg'₁" => Cfg Bool Λ'₁ σ /-- Read a vector of length `n` from the tape. -/ -def readAux : ∀ n, (Vector Bool n → Stmt'₁) → Stmt'₁ +def readAux : ∀ n, (Mathlib.Vector Bool n → Stmt'₁) → Stmt'₁ | 0, f => f Vector.nil | i + 1, f => Stmt.branch (fun a _ ↦ a) (Stmt.move Dir.right <| readAux i fun v ↦ f (true ::ᵥ v)) (Stmt.move Dir.right <| readAux i fun v ↦ f (false ::ᵥ v)) -variable {n : ℕ} (enc : Γ → Vector Bool n) (dec : Vector Bool n → Γ) +variable {n : ℕ} (enc : Γ → Mathlib.Vector Bool n) (dec : Mathlib.Vector Bool n → Γ) /-- A move left or right corresponds to `n` moves across the super-cell. -/ def move (d : Dir) (q : Stmt'₁) : Stmt'₁ := @@ -1530,7 +1530,8 @@ theorem supportsStmt_write {S : Finset Λ'₁} {l : List Bool} {q : Stmt'₁} : theorem supportsStmt_read {S : Finset Λ'₁} : ∀ {f : Γ → Stmt'₁}, (∀ a, SupportsStmt S (f a)) → SupportsStmt S (read dec f) := suffices - ∀ (i) (f : Vector Bool i → Stmt'₁), (∀ v, SupportsStmt S (f v)) → SupportsStmt S (readAux i f) + ∀ (i) (f : Mathlib.Vector Bool i → Stmt'₁), + (∀ v, SupportsStmt S (f v)) → SupportsStmt S (readAux i f) from fun hf ↦ this n _ (by intro; simp only [supportsStmt_move, hf]) fun i f hf ↦ by induction' i with i IH; · exact hf _ @@ -2437,7 +2438,7 @@ theorem tr_respects_aux {q v T k} {S : ∀ k, List (Γ k)} obtain ⟨T', hT', hrun⟩ := tr_respects_aux₂ (Λ := Λ) hT o have := hgo.tail' rfl rw [tr, TM1.stepAux, Tape.move_right_n_head, Tape.mk'_nth_nat, addBottom_nth_snd, - stk_nth_val _ (hT k), List.getElem?_len_le (le_of_eq (List.length_reverse _)), + stk_nth_val _ (hT k), List.getElem?_eq_none (le_of_eq (List.length_reverse _)), Option.isNone, cond, hrun, TM1.stepAux] at this obtain ⟨c, gc, rc⟩ := IH hT' refine ⟨c, gc, (this.to₀.trans (tr_respects_aux₃ M _) c (TransGen.head' rfl ?_)).to_reflTransGen⟩ diff --git a/Mathlib/Condensed/Discrete/Module.lean b/Mathlib/Condensed/Discrete/Module.lean index 5657c6d51579e..75760ce80c094 100644 --- a/Mathlib/Condensed/Discrete/Module.lean +++ b/Mathlib/Condensed/Discrete/Module.lean @@ -40,8 +40,8 @@ constant maps. def functorToPresheaves : ModuleCat.{max u w} R ⥤ ((CompHausLike.{u} P)ᵒᵖ ⥤ ModuleCat R) where obj X := { obj := fun ⟨S⟩ ↦ ModuleCat.of R (LocallyConstant S X) - map := fun f ↦ comapₗ R f.unop } - map f := { app := fun S ↦ mapₗ R f } + map := fun f ↦ ModuleCat.ofHom (comapₗ R f.unop) } + map f := { app := fun S ↦ ModuleCat.ofHom (mapₗ R f.hom) } variable [HasExplicitFiniteCoproducts.{0} P] [HasExplicitPullbacks.{u} P] (hs : ∀ ⦃X Y : CompHausLike P⦄ (f : X ⟶ Y), EffectiveEpi f → Function.Surjective f) @@ -79,8 +79,8 @@ abbrev functor : ModuleCat R ⥤ CondensedMod.{u} R := /-- Auxiliary definition for `functorIsoDiscrete`. -/ noncomputable def functorIsoDiscreteAux₁ (M : ModuleCat.{u+1} R) : M ≅ (ModuleCat.of R (LocallyConstant (CompHaus.of PUnit.{u+1}) M)) where - hom := constₗ R - inv := evalₗ R PUnit.unit + hom := ModuleCat.ofHom (constₗ R) + inv := ModuleCat.ofHom (evalₗ R PUnit.unit) /-- Auxiliary definition for `functorIsoDiscrete`. -/ noncomputable def functorIsoDiscreteAux₂ (M : ModuleCat R) : @@ -186,8 +186,8 @@ abbrev functor : ModuleCat R ⥤ LightCondMod.{u} R := /-- Auxiliary definition for `functorIsoDiscrete`. -/ noncomputable def functorIsoDiscreteAux₁ (M : ModuleCat.{u} R) : M ≅ (ModuleCat.of R (LocallyConstant (LightProfinite.of PUnit.{u+1}) M)) where - hom := constₗ R - inv := evalₗ R PUnit.unit + hom := ModuleCat.ofHom (constₗ R) + inv := ModuleCat.ofHom (evalₗ R PUnit.unit) /-- Auxiliary definition for `functorIsoDiscrete`. -/ noncomputable def functorIsoDiscreteAux₂ (M : ModuleCat.{u} R) : diff --git a/Mathlib/Control/Random.lean b/Mathlib/Control/Random.lean index c83ecbaba193b..fb87c58b85783 100644 --- a/Mathlib/Control/Random.lean +++ b/Mathlib/Control/Random.lean @@ -93,7 +93,7 @@ def randBound (α : Type u) (BoundedRandom.randomR lo hi h : RandGT g _ _) def randFin {n : Nat} [RandomGen g] : RandGT g m (Fin n.succ) := - fun ⟨g⟩ ↦ pure <| randNat g 0 n |>.map Fin.ofNat ULift.up + fun ⟨g⟩ ↦ pure <| randNat g 0 n |>.map (Fin.ofNat' _) ULift.up instance {n : Nat} : Random m (Fin n.succ) where random := randFin diff --git a/Mathlib/Data/Analysis/Filter.lean b/Mathlib/Data/Analysis/Filter.lean index 46a34c12aec98..39e01fe198302 100644 --- a/Mathlib/Data/Analysis/Filter.lean +++ b/Mathlib/Data/Analysis/Filter.lean @@ -286,7 +286,7 @@ protected def iSup {f : α → Filter β} (F : ∀ i, (f i).Realizer) : (⨆ i, ⟨fun ⟨_, f⟩ i ↦ f i ⟨⟩, fun f ↦ ⟨(), fun i _ ↦ f i⟩, fun _ ↦ rfl, fun _ ↦ rfl⟩ /-- Construct a realizer for the product of filters -/ -protected def prod {f g : Filter α} (F : f.Realizer) (G : g.Realizer) : (f.prod g).Realizer := +protected def prod {f g : Filter α} (F : f.Realizer) (G : g.Realizer) : (f ×ˢ g).Realizer := (F.comap _).inf (G.comap _) theorem le_iff {f g : Filter α} (F : f.Realizer) (G : g.Realizer) : diff --git a/Mathlib/Data/Bool/Basic.lean b/Mathlib/Data/Bool/Basic.lean index 1b5e3ff38f835..5f5bfc9ba28c8 100644 --- a/Mathlib/Data/Bool/Basic.lean +++ b/Mathlib/Data/Bool/Basic.lean @@ -103,9 +103,9 @@ theorem coe_xor_iff (a b : Bool) : xor a b ↔ Xor' (a = true) (b = true) := by end -@[deprecated (since := "2024-06-07")] alias decide_True := decide_true_eq_true +@[deprecated (since := "2024-06-07")] alias decide_True := decide_true -@[deprecated (since := "2024-06-07")] alias decide_False := decide_false_eq_false +@[deprecated (since := "2024-06-07")] alias decide_False := decide_false @[deprecated (since := "2024-06-07")] alias coe_decide := decide_eq_true_iff diff --git a/Mathlib/Data/Complex/Basic.lean b/Mathlib/Data/Complex/Basic.lean index e1d6851ed9e2f..c14f55bdce967 100644 --- a/Mathlib/Data/Complex/Basic.lean +++ b/Mathlib/Data/Complex/Basic.lean @@ -283,7 +283,7 @@ theorem equivRealProdAddHom_symm_apply (p : ℝ × ℝ) : diamond from the other actions they inherit through the `ℝ`-action on `ℂ` and action transitivity defined in `Data.Complex.Module`. -/ instance : Nontrivial ℂ := - pullback_nonzero re rfl rfl + domain_nontrivial re rfl rfl -- Porting note: moved from `Module/Data/Complex/Basic.lean` namespace SMul diff --git a/Mathlib/Data/Countable/Basic.lean b/Mathlib/Data/Countable/Basic.lean index caecc1a3b4c19..e9840f762cea5 100644 --- a/Mathlib/Data/Countable/Basic.lean +++ b/Mathlib/Data/Countable/Basic.lean @@ -5,6 +5,7 @@ Authors: Yury Kudryashov -/ import Mathlib.Data.Countable.Defs import Mathlib.Data.Fin.Tuple.Basic +import Mathlib.Data.ENat.Defs import Mathlib.Logic.Equiv.Nat /-! diff --git a/Mathlib/Data/DFinsupp/Lex.lean b/Mathlib/Data/DFinsupp/Lex.lean index 1b3888f712e29..3251cba793ca2 100644 --- a/Mathlib/Data/DFinsupp/Lex.lean +++ b/Mathlib/Data/DFinsupp/Lex.lean @@ -91,13 +91,13 @@ private def lt_trichotomy_rec {P : Lex (Π₀ i, α i) → Lex (Π₀ i, α i) not_mem_neLocus.mp (Finset.not_mem_of_lt_min hj <| by rwa [neLocus_comm]), hwit⟩ /-- The less-or-equal relation for the lexicographic ordering is decidable. -/ -irreducible_def Lex.decidableLE : @DecidableRel (Lex (Π₀ i, α i)) (· ≤ ·) := +irreducible_def Lex.decidableLE : DecidableRel (α := Lex (Π₀ i, α i)) (· ≤ ·) := lt_trichotomy_rec (fun h ↦ isTrue <| Or.inr h) (fun h ↦ isTrue <| Or.inl <| congr_arg _ h) fun h ↦ isFalse fun h' ↦ lt_irrefl _ (h.trans_le h') /-- The less-than relation for the lexicographic ordering is decidable. -/ -irreducible_def Lex.decidableLT : @DecidableRel (Lex (Π₀ i, α i)) (· < ·) := +irreducible_def Lex.decidableLT : DecidableRel (α := Lex (Π₀ i, α i)) (· < ·) := lt_trichotomy_rec (fun h ↦ isTrue h) (fun h ↦ isFalse h.not_lt) fun h ↦ isFalse h.asymm -- Porting note: Added `DecidableEq` for `LinearOrder`. diff --git a/Mathlib/Data/DFinsupp/Sigma.lean b/Mathlib/Data/DFinsupp/Sigma.lean index 4df5f452d103f..10d83e6df6193 100644 --- a/Mathlib/Data/DFinsupp/Sigma.lean +++ b/Mathlib/Data/DFinsupp/Sigma.lean @@ -63,14 +63,20 @@ theorem sigmaCurry_zero [∀ i j, Zero (δ i j)] : @[simp] theorem sigmaCurry_add [∀ i j, AddZeroClass (δ i j)] (f g : Π₀ (i : Σ _, _), δ i.1 i.2) : - sigmaCurry (f + g) = sigmaCurry f + sigmaCurry g := by + #adaptation_note + /-- After https://github.com/leanprover/lean4/pull/6024 + we needed to add the `(_ : Π₀ (i) (j), δ i j)` type annotation. -/ + sigmaCurry (f + g) = (sigmaCurry f + sigmaCurry g : Π₀ (i) (j), δ i j) := by ext (i j) rfl @[simp] theorem sigmaCurry_smul [Monoid γ] [∀ i j, AddMonoid (δ i j)] [∀ i j, DistribMulAction γ (δ i j)] (r : γ) (f : Π₀ (i : Σ _, _), δ i.1 i.2) : - sigmaCurry (r • f) = r • sigmaCurry f := by + #adaptation_note + /-- After https://github.com/leanprover/lean4/pull/6024 + we needed to add the `(_ : Π₀ (i) (j), δ i j)` type annotation. -/ + sigmaCurry (r • f) = (r • sigmaCurry f : Π₀ (i) (j), δ i j) := by ext (i j) rfl diff --git a/Mathlib/Data/DFinsupp/Submonoid.lean b/Mathlib/Data/DFinsupp/Submonoid.lean index 1bcd75a448f19..4af6b95649e4d 100644 --- a/Mathlib/Data/DFinsupp/Submonoid.lean +++ b/Mathlib/Data/DFinsupp/Submonoid.lean @@ -3,6 +3,7 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Kenny Lau -/ +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Group.Submonoid.Membership import Mathlib.Data.DFinsupp.BigOperators import Mathlib.Order.ConditionallyCompleteLattice.Basic diff --git a/Mathlib/Data/ENNReal/Inv.lean b/Mathlib/Data/ENNReal/Inv.lean index bccdde7f1f4ab..0a17941605844 100644 --- a/Mathlib/Data/ENNReal/Inv.lean +++ b/Mathlib/Data/ENNReal/Inv.lean @@ -543,7 +543,7 @@ theorem exists_inv_two_pow_lt (ha : a ≠ 0) : ∃ n : ℕ, 2⁻¹ ^ n < a := by refine ⟨n, lt_trans ?_ hn⟩ rw [← ENNReal.inv_pow, ENNReal.inv_lt_inv] norm_cast - exact n.lt_two_pow + exact n.lt_two_pow_self @[simp, norm_cast] theorem coe_zpow (hr : r ≠ 0) (n : ℤ) : (↑(r ^ n) : ℝ≥0∞) = (r : ℝ≥0∞) ^ n := by diff --git a/Mathlib/Data/ENat/Basic.lean b/Mathlib/Data/ENat/Basic.lean index 663a5824cbe31..5b96e88c13f2d 100644 --- a/Mathlib/Data/ENat/Basic.lean +++ b/Mathlib/Data/ENat/Basic.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov import Mathlib.Algebra.CharZero.Lemmas import Mathlib.Algebra.Order.Ring.WithTop import Mathlib.Algebra.Order.Sub.WithTop +import Mathlib.Data.ENat.Defs import Mathlib.Data.Nat.Cast.Order.Basic import Mathlib.Data.Nat.SuccPred import Mathlib.Order.Nat @@ -58,6 +59,8 @@ variable {a b c m n : ℕ∞} `ℕ → ℕ∞` is `Nat.cast`. -/ @[simp] theorem some_eq_coe : (WithTop.some : ℕ → ℕ∞) = Nat.cast := rfl +theorem coe_inj {a b : ℕ} : (a : ℕ∞) = b ↔ a = b := WithTop.coe_inj + instance : SuccAddOrder ℕ∞ where succ_eq_add_one x := by cases x <;> simp [SuccOrder.succ] @@ -87,6 +90,29 @@ theorem coe_sub (m n : ℕ) : ↑(m - n) = (m - n : ℕ∞) := theorem top_pow {n : ℕ} (n_pos : 0 < n) : (⊤ : ℕ∞) ^ n = ⊤ := WithTop.top_pow n_pos +/-- Convert a `ℕ∞` to a `ℕ` using a proof that it is not infinite. -/ +def lift (x : ℕ∞) (h : x < ⊤) : ℕ := WithTop.untop x (WithTop.lt_top_iff_ne_top.mp h) + +@[simp] theorem coe_lift (x : ℕ∞) (h : x < ⊤) : (lift x h : ℕ∞) = x := + WithTop.coe_untop x (WithTop.lt_top_iff_ne_top.mp h) +@[simp] theorem lift_coe (n : ℕ) : lift (n : ℕ∞) (WithTop.coe_lt_top n) = n := rfl +@[simp] theorem lift_lt_iff {x : ℕ∞} {h} {n : ℕ} : lift x h < n ↔ x < n := WithTop.untop_lt_iff _ +@[simp] theorem lift_le_iff {x : ℕ∞} {h} {n : ℕ} : lift x h ≤ n ↔ x ≤ n := WithTop.untop_le_iff _ +@[simp] theorem lt_lift_iff {x : ℕ} {n : ℕ∞} {h} : x < lift n h ↔ x < n := WithTop.lt_untop_iff _ +@[simp] theorem le_lift_iff {x : ℕ} {n : ℕ∞} {h} : x ≤ lift n h ↔ x ≤ n := WithTop.le_untop_iff _ + +@[simp] theorem lift_zero : lift 0 (WithTop.coe_lt_top 0) = 0 := rfl +@[simp] theorem lift_one : lift 1 (WithTop.coe_lt_top 1) = 1 := rfl +@[simp] theorem lift_ofNat (n : ℕ) [n.AtLeastTwo] : + lift (no_index (OfNat.ofNat n)) (WithTop.coe_lt_top n) = OfNat.ofNat n := rfl + +@[simp] theorem add_lt_top {a b : ℕ∞} : a + b < ⊤ ↔ a < ⊤ ∧ b < ⊤ := WithTop.add_lt_top + +@[simp] theorem lift_add (a b : ℕ∞) (h : a + b < ⊤) : + lift (a + b) h = lift a (add_lt_top.1 h).1 + lift b (add_lt_top.1 h).2 := by + apply coe_inj.1 + simp + instance canLift : CanLift ℕ∞ ℕ (↑) (· ≠ ⊤) := WithTop.canLift instance : WellFoundedRelation ℕ∞ where @@ -261,6 +287,10 @@ lemma not_lt_zero (n : ℕ∞) : ¬ n < 0 := by lemma coe_lt_top (n : ℕ) : (n : ℕ∞) < ⊤ := WithTop.coe_lt_top n +lemma coe_lt_coe {n m : ℕ} : (n : ℕ∞) < (m : ℕ∞) ↔ n < m := by simp + +lemma coe_le_coe {n m : ℕ} : (n : ℕ∞) ≤ (m : ℕ∞) ↔ n ≤ m := by simp + @[elab_as_elim] theorem nat_induction {P : ℕ∞ → Prop} (a : ℕ∞) (h0 : P 0) (hsuc : ∀ n : ℕ, P n → P n.succ) (htop : (∀ n : ℕ, P n) → P ⊤) : P a := by diff --git a/Mathlib/Data/ENat/Defs.lean b/Mathlib/Data/ENat/Defs.lean new file mode 100644 index 0000000000000..479ef16a06353 --- /dev/null +++ b/Mathlib/Data/ENat/Defs.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Simon Hudon, Yury Kudryashov +-/ + +import Mathlib.Data.Nat.Notation +import Mathlib.Order.TypeTags + +/-! # Definition and notation for extended natural numbers -/ + +/-- Extended natural numbers `ℕ∞ = WithTop ℕ`. -/ +def ENat : Type := WithTop ℕ deriving Top, Inhabited + +@[inherit_doc] notation "ℕ∞" => ENat + +namespace ENat + +instance instNatCast : NatCast ℕ∞ := ⟨WithTop.some⟩ + +-- Porting note (https://github.com/leanprover-community/mathlib4/issues/11445): new definition copied from `WithTop` +/-- Recursor for `ENat` using the preferred forms `⊤` and `↑a`. -/ +@[elab_as_elim, induction_eliminator, cases_eliminator] +def recTopCoe {C : ℕ∞ → Sort*} (top : C ⊤) (coe : ∀ a : ℕ, C a) : ∀ n : ℕ∞, C n + | none => top + | Option.some a => coe a + +@[simp] +theorem recTopCoe_top {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) : + @recTopCoe C d f ⊤ = d := + rfl + +@[simp] +theorem recTopCoe_coe {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) (x : ℕ) : + @recTopCoe C d f ↑x = f x := + rfl + +end ENat diff --git a/Mathlib/Data/Fin/Parity.lean b/Mathlib/Data/Fin/Parity.lean index bd4b7b0b71e3b..2a2a76ca7d8b1 100644 --- a/Mathlib/Data/Fin/Parity.lean +++ b/Mathlib/Data/Fin/Parity.lean @@ -94,4 +94,10 @@ lemma not_even_iff_odd_of_even {n : ℕ} [NeZero n] (hn : Even n) {k : Fin n} : rw [even_iff_of_even hn, odd_iff_of_even hn] exact Nat.not_even_iff_odd +lemma odd_add_one_iff_even {n : ℕ} [NeZero n] {k : Fin n} : Odd (k + 1) ↔ Even k := + ⟨fun ⟨k, hk⟩ ↦ add_right_cancel hk ▸ even_two_mul k, Even.add_one⟩ + +lemma even_add_one_iff_odd {n : ℕ} [NeZero n] {k : Fin n} : Even (k + 1) ↔ Odd k := + ⟨fun ⟨k, hk⟩ ↦ eq_sub_iff_add_eq.mpr hk ▸ (even_add_self k).sub_odd odd_one, Odd.add_one⟩ + end Fin diff --git a/Mathlib/Data/Fin/Tuple/Take.lean b/Mathlib/Data/Fin/Tuple/Take.lean index 1ff923b04788e..462351c63a8d1 100644 --- a/Mathlib/Data/Fin/Tuple/Take.lean +++ b/Mathlib/Data/Fin/Tuple/Take.lean @@ -3,7 +3,6 @@ Copyright (c) 2024 Quang Dao. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Quang Dao -/ -import Batteries.Data.List.OfFn import Mathlib.Data.Fin.Tuple.Basic /-! diff --git a/Mathlib/Data/Fin/VecNotation.lean b/Mathlib/Data/Fin/VecNotation.lean index 1b8ca2379a123..aeb31bb6c4a94 100644 --- a/Mathlib/Data/Fin/VecNotation.lean +++ b/Mathlib/Data/Fin/VecNotation.lean @@ -167,7 +167,6 @@ theorem range_cons_cons_empty (x y : α) (u : Fin 0 → α) : Set.range (vecCons x <| vecCons y u) = {x, y} := by rw [range_cons, range_cons_empty, Set.singleton_union] -@[simp] theorem vecCons_const (a : α) : (vecCons a fun _ : Fin n => a) = fun _ => a := funext <| Fin.forall_iff_succ.2 ⟨rfl, cons_val_succ _ _⟩ diff --git a/Mathlib/Data/Finite/Card.lean b/Mathlib/Data/Finite/Card.lean index fb6afe0f1c2f9..a1193eb881ff5 100644 --- a/Mathlib/Data/Finite/Card.lean +++ b/Mathlib/Data/Finite/Card.lean @@ -46,7 +46,7 @@ theorem Nat.card_eq (α : Type*) : Nat.card α = if _ : Finite α then @Fintype.card α (Fintype.ofFinite α) else 0 := by cases finite_or_infinite α · letI := Fintype.ofFinite α - simp only [*, Nat.card_eq_fintype_card, dif_pos] + simp only [this, *, Nat.card_eq_fintype_card, dif_pos] · simp only [*, card_eq_zero_of_infinite, not_finite_iff_infinite.mpr, dite_false] theorem Finite.card_pos_iff [Finite α] : 0 < Nat.card α ↔ Nonempty α := by @@ -162,18 +162,15 @@ theorem card_subtype_lt [Finite α] {p : α → Prop} {x : α} (hx : ¬p x) : end Finite -namespace PartENat +namespace ENat theorem card_eq_coe_natCard (α : Type*) [Finite α] : card α = Nat.card α := by - unfold PartENat.card + unfold ENat.card apply symm - rw [Cardinal.natCast_eq_toPartENat_iff] + rw [Cardinal.natCast_eq_toENat_iff] exact Finite.cast_card_eq_mk - -@[deprecated (since := "2024-05-25")] alias card_eq_coe_nat_card := card_eq_coe_natCard - -end PartENat +end ENat namespace Set diff --git a/Mathlib/Data/Finset/Defs.lean b/Mathlib/Data/Finset/Defs.lean index 694a1fbcf2f29..7acf539ddfefc 100644 --- a/Mathlib/Data/Finset/Defs.lean +++ b/Mathlib/Data/Finset/Defs.lean @@ -213,6 +213,8 @@ instance partialOrder : PartialOrder (Finset α) where le_trans _ _ _ hst htu _ ha := htu <| hst ha le_antisymm _ _ hst hts := ext fun _ => ⟨@hst _, @hts _⟩ +theorem subset_of_le : s ≤ t → s ⊆ t := id + instance : IsRefl (Finset α) (· ⊆ ·) := show IsRefl (Finset α) (· ≤ ·) by infer_instance @@ -368,16 +370,16 @@ instance decidableDforallFinset {p : ∀ a ∈ s, Prop} [_hp : ∀ (a) (h : a -- Porting note: In lean3, `decidableDforallFinset` was picked up when decidability of `s ⊆ t` was -- needed. In lean4 it seems this is not the case. -instance instDecidableRelSubset [DecidableEq α] : @DecidableRel (Finset α) (· ⊆ ·) := +instance instDecidableRelSubset [DecidableEq α] : DecidableRel (α := Finset α) (· ⊆ ·) := fun _ _ ↦ decidableDforallFinset -instance instDecidableRelSSubset [DecidableEq α] : @DecidableRel (Finset α) (· ⊂ ·) := +instance instDecidableRelSSubset [DecidableEq α] : DecidableRel (α := Finset α) (· ⊂ ·) := fun _ _ ↦ instDecidableAnd -instance instDecidableLE [DecidableEq α] : @DecidableRel (Finset α) (· ≤ ·) := +instance instDecidableLE [DecidableEq α] : DecidableRel (α := Finset α) (· ≤ ·) := instDecidableRelSubset -instance instDecidableLT [DecidableEq α] : @DecidableRel (Finset α) (· < ·) := +instance instDecidableLT [DecidableEq α] : DecidableRel (α := Finset α) (· < ·) := instDecidableRelSSubset instance decidableDExistsFinset {p : ∀ a ∈ s, Prop} [_hp : ∀ (a) (h : a ∈ s), Decidable (p a h)] : diff --git a/Mathlib/Data/Finset/Filter.lean b/Mathlib/Data/Finset/Filter.lean index d42d8d22414fa..746efb1723405 100644 --- a/Mathlib/Data/Finset/Filter.lean +++ b/Mathlib/Data/Finset/Filter.lean @@ -214,6 +214,15 @@ lemma _root_.Set.pairwiseDisjoint_filter [DecidableEq β] (f : α → β) (s : S obtain ⟨-, rfl⟩ : x ∈ t ∧ f x = j := by simpa using hj hx contradiction +theorem disjoint_filter_and_not_filter : + Disjoint (s.filter (fun x ↦ p x ∧ ¬q x)) (s.filter (fun x ↦ q x ∧ ¬p x)) := by + intro _ htp htq + simp [bot_eq_empty, le_eq_subset, subset_empty] + by_contra hn + rw [← not_nonempty_iff_eq_empty, not_not] at hn + obtain ⟨_, hx⟩ := hn + exact (mem_filter.mp (htq hx)).2.2 (mem_filter.mp (htp hx)).2.1 + variable {p q} lemma filter_inj : s.filter p = t.filter p ↔ ∀ ⦃a⦄, p a → (a ∈ s ↔ a ∈ t) := by diff --git a/Mathlib/Data/Finset/Image.lean b/Mathlib/Data/Finset/Image.lean index 5b0af20456dff..f5732b4cbc6e6 100644 --- a/Mathlib/Data/Finset/Image.lean +++ b/Mathlib/Data/Finset/Image.lean @@ -313,8 +313,10 @@ theorem mem_image : b ∈ s.image f ↔ ∃ a ∈ s, f a = b := by theorem mem_image_of_mem (f : α → β) {a} (h : a ∈ s) : f a ∈ s.image f := mem_image.2 ⟨_, h, rfl⟩ -theorem forall_image {p : β → Prop} : (∀ b ∈ s.image f, p b) ↔ ∀ a ∈ s, p (f a) := by - simp only [mem_image, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂] +lemma forall_mem_image {p : β → Prop} : (∀ y ∈ s.image f, p y) ↔ ∀ ⦃x⦄, x ∈ s → p (f x) := by simp +lemma exists_mem_image {p : β → Prop} : (∃ y ∈ s.image f, p y) ↔ ∃ x ∈ s, p (f x) := by simp + +@[deprecated (since := "2024-11-23")] alias forall_image := forall_mem_image theorem map_eq_image (f : α ↪ β) (s : Finset α) : s.map f = s.image f := eq_of_veq (s.map f).2.dedup.symm diff --git a/Mathlib/Data/Finset/Insert.lean b/Mathlib/Data/Finset/Insert.lean index 1b93ae1f21cc9..8d5f792fbf340 100644 --- a/Mathlib/Data/Finset/Insert.lean +++ b/Mathlib/Data/Finset/Insert.lean @@ -216,6 +216,10 @@ instance (i : α) : Unique ({i} : Finset α) where @[simp] lemma default_singleton (i : α) : ((default : ({i} : Finset α)) : α) = i := rfl +instance Nontrivial.instDecidablePred [DecidableEq α] : + DecidablePred (Finset.Nontrivial (α := α)) := + inferInstanceAs (DecidablePred fun s ↦ ∃ a ∈ s, ∃ b ∈ s, a ≠ b) + end Singleton /-! ### cons -/ @@ -411,9 +415,11 @@ theorem insert_ne_self : insert a s ≠ s ↔ a ∉ s := theorem pair_eq_singleton (a : α) : ({a, a} : Finset α) = {a} := insert_eq_of_mem <| mem_singleton_self _ -theorem Insert.comm (a b : α) (s : Finset α) : insert a (insert b s) = insert b (insert a s) := +theorem insert_comm (a b : α) (s : Finset α) : insert a (insert b s) = insert b (insert a s) := ext fun x => by simp only [mem_insert, or_left_comm] +@[deprecated (since := "2024-11-29")] alias Insert.comm := insert_comm + @[norm_cast] theorem coe_pair {a b : α} : (({a, b} : Finset α) : Set α) = {a, b} := by ext @@ -424,7 +430,7 @@ theorem coe_eq_pair {s : Finset α} {a b : α} : (s : Set α) = {a, b} ↔ s = { rw [← coe_pair, coe_inj] theorem pair_comm (a b : α) : ({a, b} : Finset α) = {b, a} := - Insert.comm a b ∅ + insert_comm a b ∅ theorem insert_idem (a : α) (s : Finset α) : insert a (insert a s) = insert a s := ext fun x => by simp only [mem_insert, ← or_assoc, or_self_iff] diff --git a/Mathlib/Data/Finset/Lattice/Fold.lean b/Mathlib/Data/Finset/Lattice/Fold.lean index 404b2ac9105b3..506bb676f71b9 100644 --- a/Mathlib/Data/Finset/Lattice/Fold.lean +++ b/Mathlib/Data/Finset/Lattice/Fold.lean @@ -18,8 +18,8 @@ This file is concerned with folding binary lattice operations over finsets. For the special case of maximum and minimum of a finset, see Max.lean. -See also SetLattice.lean, which is instead concerned with how big lattice or set operations behave -when indexed by a finset. +See also `Mathlib/Order/CompleteLattice/Finset.lean`, which is instead concerned with how big +lattice or set operations behave when indexed by a finset. -/ assert_not_exists OrderedCommMonoid @@ -634,6 +634,22 @@ protected theorem sup_lt_iff (ha : ⊥ < a) : s.sup f < a ↔ ∀ b ∈ s, f b < Finset.cons_induction_on s (fun _ => ha) fun c t hc => by simpa only [sup_cons, sup_lt_iff, mem_cons, forall_eq_or_imp] using And.imp_right⟩ +theorem sup_mem_of_nonempty (hs : s.Nonempty) : s.sup f ∈ f '' s := by + classical + induction s using Finset.induction with + | empty => exfalso; simp only [Finset.not_nonempty_empty] at hs + | @insert a s _ h => + rw [Finset.sup_insert (b := a) (s := s) (f := f)] + by_cases hs : s = ∅ + · simp [hs] + · rw [← ne_eq, ← Finset.nonempty_iff_ne_empty] at hs + simp only [Finset.coe_insert] + rcases le_total (f a) (s.sup f) with (ha | ha) + · rw [sup_eq_right.mpr ha] + exact Set.image_mono (Set.subset_insert a s) (h hs) + · rw [sup_eq_left.mpr ha] + apply Set.mem_image_of_mem _ (Set.mem_insert a ↑s) + end OrderBot section OrderTop @@ -1106,6 +1122,11 @@ section LinearOrder variable [LinearOrder α] {s : Finset ι} (H : s.Nonempty) {f : ι → α} {a : α} +theorem comp_sup_eq_sup_comp_of_nonempty [OrderBot α] [SemilatticeSup β] [OrderBot β] + {g : α → β} (mono_g : Monotone g) (H : s.Nonempty) : g (s.sup f) = s.sup (g ∘ f) := by + rw [← Finset.sup'_eq_sup H, ← Finset.sup'_eq_sup H] + exact Finset.comp_sup'_eq_sup'_comp H g (fun x y ↦ Monotone.map_sup mono_g x y) + @[simp] theorem le_sup'_iff : a ≤ s.sup' H f ↔ ∃ b ∈ s, a ≤ f b := by rw [← WithBot.coe_le_coe, coe_sup', Finset.le_sup_iff (WithBot.bot_lt_coe a)] diff --git a/Mathlib/Data/Finset/Lattice/Lemmas.lean b/Mathlib/Data/Finset/Lattice/Lemmas.lean index ad6b5a9afb949..c5783884b4b5a 100644 --- a/Mathlib/Data/Finset/Lattice/Lemmas.lean +++ b/Mathlib/Data/Finset/Lattice/Lemmas.lean @@ -155,7 +155,9 @@ lemma inter_singleton {a : α} {s : Finset α} : s ∩ {a} = if a ∈ s then {a} else ∅ := by split_ifs with h <;> simp [h] -lemma union_eq_empty : s ∪ t = ∅ ↔ s = ∅ ∧ t = ∅ := sup_eq_bot_iff +@[simp] lemma union_eq_empty : s ∪ t = ∅ ↔ s = ∅ ∧ t = ∅ := sup_eq_bot_iff +@[simp] lemma union_nonempty : (s ∪ t).Nonempty ↔ s.Nonempty ∨ t.Nonempty := + mod_cast Set.union_nonempty (α := α) (s := s) (t := t) theorem insert_union_comm (s t : Finset α) (a : α) : insert a s ∪ t = s ∪ insert a t := by rw [insert_union, union_insert] diff --git a/Mathlib/Data/Finset/NAry.lean b/Mathlib/Data/Finset/NAry.lean index 1ef61280f4ffc..28a21e494d1a0 100644 --- a/Mathlib/Data/Finset/NAry.lean +++ b/Mathlib/Data/Finset/NAry.lean @@ -83,13 +83,19 @@ theorem image_subset_image₂_left (hb : b ∈ t) : s.image (fun a => f a b) ⊆ theorem image_subset_image₂_right (ha : a ∈ s) : t.image (fun b => f a b) ⊆ image₂ f s t := image_subset_iff.2 fun _ => mem_image₂_of_mem ha -theorem forall_image₂_iff {p : γ → Prop} : +lemma forall_mem_image₂ {p : γ → Prop} : (∀ z ∈ image₂ f s t, p z) ↔ ∀ x ∈ s, ∀ y ∈ t, p (f x y) := by - simp_rw [← mem_coe, coe_image₂, forall_image2_iff] + simp_rw [← mem_coe, coe_image₂, forall_mem_image2] + +lemma exists_mem_image₂ {p : γ → Prop} : + (∃ z ∈ image₂ f s t, p z) ↔ ∃ x ∈ s, ∃ y ∈ t, p (f x y) := by + simp_rw [← mem_coe, coe_image₂, exists_mem_image2] + +@[deprecated (since := "2024-11-23")] alias forall_image₂_iff := forall_mem_image₂ @[simp] theorem image₂_subset_iff : image₂ f s t ⊆ u ↔ ∀ x ∈ s, ∀ y ∈ t, f x y ∈ u := - forall_image₂_iff + forall_mem_image₂ theorem image₂_subset_iff_left : image₂ f s t ⊆ u ↔ ∀ a ∈ s, (t.image fun b => f a b) ⊆ u := by simp_rw [image₂_subset_iff, image_subset_iff] @@ -504,10 +510,10 @@ section SemilatticeSup variable [SemilatticeSup δ] -@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_image₂_iff` +@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_mem_image₂` lemma sup'_image₂_le {g : γ → δ} {a : δ} (h : (image₂ f s t).Nonempty) : sup' (image₂ f s t) h g ≤ a ↔ ∀ x ∈ s, ∀ y ∈ t, g (f x y) ≤ a := by - rw [sup'_le_iff, forall_image₂_iff] + rw [sup'_le_iff, forall_mem_image₂] lemma sup'_image₂_left (g : γ → δ) (h : (image₂ f s t).Nonempty) : sup' (image₂ f s t) h g = @@ -521,10 +527,10 @@ lemma sup'_image₂_right (g : γ → δ) (h : (image₂ f s t).Nonempty) : variable [OrderBot δ] -@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_image₂_iff` +@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_mem_image₂` lemma sup_image₂_le {g : γ → δ} {a : δ} : sup (image₂ f s t) g ≤ a ↔ ∀ x ∈ s, ∀ y ∈ t, g (f x y) ≤ a := by - rw [Finset.sup_le_iff, forall_image₂_iff] + rw [Finset.sup_le_iff, forall_mem_image₂] variable (s t) @@ -540,10 +546,10 @@ section SemilatticeInf variable [SemilatticeInf δ] -@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_image₂_iff` +@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_mem_image₂` lemma le_inf'_image₂ {g : γ → δ} {a : δ} (h : (image₂ f s t).Nonempty) : a ≤ inf' (image₂ f s t) h g ↔ ∀ x ∈ s, ∀ y ∈ t, a ≤ g (f x y) := by - rw [le_inf'_iff, forall_image₂_iff] + rw [le_inf'_iff, forall_mem_image₂] lemma inf'_image₂_left (g : γ → δ) (h : (image₂ f s t).Nonempty) : inf' (image₂ f s t) h g = @@ -557,7 +563,7 @@ lemma inf'_image₂_right (g : γ → δ) (h : (image₂ f s t).Nonempty) : variable [OrderTop δ] -@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_image₂_iff` +@[simp (default + 1)] -- otherwise `simp` doesn't use `forall_mem_image₂` lemma le_inf_image₂ {g : γ → δ} {a : δ} : a ≤ inf (image₂ f s t) g ↔ ∀ x ∈ s, ∀ y ∈ t, a ≤ g (f x y) := sup_image₂_le (δ := δᵒᵈ) diff --git a/Mathlib/Data/Finset/SDiff.lean b/Mathlib/Data/Finset/SDiff.lean index 52b4f4ac894a3..1b6228553e58b 100644 --- a/Mathlib/Data/Finset/SDiff.lean +++ b/Mathlib/Data/Finset/SDiff.lean @@ -111,11 +111,11 @@ theorem sdiff_empty : s \ ∅ = s := @[mono, gcongr] theorem sdiff_subset_sdiff (hst : s ⊆ t) (hvu : v ⊆ u) : s \ u ⊆ t \ v := - sdiff_le_sdiff hst hvu + subset_of_le (sdiff_le_sdiff hst hvu) theorem sdiff_subset_sdiff_iff_subset {r : Finset α} (hs : s ⊆ r) (ht : t ⊆ r) : - r \ s ⊆ r \ t ↔ t ⊆ s := - sdiff_le_sdiff_iff_le hs ht + r \ s ⊆ r \ t ↔ t ⊆ s := by + simpa only [← le_eq_subset] using sdiff_le_sdiff_iff_le hs ht @[simp, norm_cast] theorem coe_sdiff (s₁ s₂ : Finset α) : ↑(s₁ \ s₂) = (s₁ \ s₂ : Set α) := diff --git a/Mathlib/Data/Finset/Sort.lean b/Mathlib/Data/Finset/Sort.lean index 7e7f3fc62d674..d4354b5039a5b 100644 --- a/Mathlib/Data/Finset/Sort.lean +++ b/Mathlib/Data/Finset/Sort.lean @@ -113,7 +113,7 @@ theorem sorted_zero_eq_min'_aux (s : Finset α) (h : 0 < (s.sort (· ≤ ·)).le obtain ⟨i, hi⟩ : ∃ i, l.get i = s.min' H := List.mem_iff_get.1 this rw [← hi] exact (s.sort_sorted (· ≤ ·)).rel_get_of_le (Nat.zero_le i) - · have : l.get ⟨0, h⟩ ∈ s := (Finset.mem_sort (α := α) (· ≤ ·)).1 (List.get_mem l 0 h) + · have : l.get ⟨0, h⟩ ∈ s := (Finset.mem_sort (α := α) (· ≤ ·)).1 (List.get_mem l _) exact s.min'_le _ this theorem sorted_zero_eq_min' {s : Finset α} {h : 0 < (s.sort (· ≤ ·)).length} : @@ -130,7 +130,7 @@ theorem sorted_last_eq_max'_aux (s : Finset α) let l := s.sort (· ≤ ·) apply le_antisymm · have : l.get ⟨(s.sort (· ≤ ·)).length - 1, h⟩ ∈ s := - (Finset.mem_sort (α := α) (· ≤ ·)).1 (List.get_mem l _ h) + (Finset.mem_sort (α := α) (· ≤ ·)).1 (List.get_mem l _) exact s.le_max' _ this · have : s.max' H ∈ l := (Finset.mem_sort (α := α) (· ≤ ·)).mpr (s.max'_mem H) obtain ⟨i, hi⟩ : ∃ i, l.get i = s.max' H := List.mem_iff_get.1 this diff --git a/Mathlib/Data/Finset/Sups.lean b/Mathlib/Data/Finset/Sups.lean index 0b2bf2e8a4359..04324a2636c5c 100644 --- a/Mathlib/Data/Finset/Sups.lean +++ b/Mathlib/Data/Finset/Sups.lean @@ -91,7 +91,7 @@ lemma image_subset_sups_left : b ∈ t → s.image (· ⊔ b) ⊆ s ⊻ t := ima lemma image_subset_sups_right : a ∈ s → t.image (a ⊔ ·) ⊆ s ⊻ t := image_subset_image₂_right theorem forall_sups_iff {p : α → Prop} : (∀ c ∈ s ⊻ t, p c) ↔ ∀ a ∈ s, ∀ b ∈ t, p (a ⊔ b) := - forall_image₂_iff + forall_mem_image₂ @[simp] theorem sups_subset_iff : s ⊻ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊔ b ∈ u := @@ -159,7 +159,7 @@ lemma sups_subset_self : s ⊻ s ⊆ s ↔ SupClosed (s : Set α) := sups_subset @[simp] lemma univ_sups_univ [Fintype α] : (univ : Finset α) ⊻ univ = univ := by simp -lemma filter_sups_le [@DecidableRel α (· ≤ ·)] (s t : Finset α) (a : α) : +lemma filter_sups_le [DecidableRel (α := α) (· ≤ ·)] (s t : Finset α) (a : α) : {b ∈ s ⊻ t | b ≤ a} = {b ∈ s | b ≤ a} ⊻ {b ∈ t | b ≤ a} := by simp only [← coe_inj, coe_filter, coe_sups, ← mem_coe, Set.sep_sups_le] @@ -236,7 +236,7 @@ lemma image_subset_infs_left : b ∈ t → s.image (· ⊓ b) ⊆ s ⊼ t := ima lemma image_subset_infs_right : a ∈ s → t.image (a ⊓ ·) ⊆ s ⊼ t := image_subset_image₂_right theorem forall_infs_iff {p : α → Prop} : (∀ c ∈ s ⊼ t, p c) ↔ ∀ a ∈ s, ∀ b ∈ t, p (a ⊓ b) := - forall_image₂_iff + forall_mem_image₂ @[simp] theorem infs_subset_iff : s ⊼ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊓ b ∈ u := @@ -304,7 +304,7 @@ lemma infs_self_subset : s ⊼ s ⊆ s ↔ InfClosed (s : Set α) := infs_subset @[simp] lemma univ_infs_univ [Fintype α] : (univ : Finset α) ⊼ univ = univ := by simp -lemma filter_infs_le [@DecidableRel α (· ≤ ·)] (s t : Finset α) (a : α) : +lemma filter_infs_le [DecidableRel (α := α) (· ≤ ·)] (s t : Finset α) (a : α) : {b ∈ s ⊼ t | a ≤ b} = {b ∈ s | a ≤ b} ⊼ {b ∈ t | a ≤ b} := by simp only [← coe_inj, coe_filter, coe_infs, ← mem_coe, Set.sep_infs_le] @@ -388,7 +388,8 @@ end Finset section DisjSups variable [DecidableEq α] -variable [SemilatticeSup α] [OrderBot α] [@DecidableRel α Disjoint] (s s₁ s₂ t t₁ t₂ u : Finset α) +variable [SemilatticeSup α] [OrderBot α] [DecidableRel (α := α) Disjoint] + (s s₁ s₂ t t₁ t₂ u : Finset α) /-- The finset of elements of the form `a ⊔ b` where `a ∈ s`, `b ∈ t` and `a` and `b` are disjoint. -/ @@ -486,7 +487,7 @@ open FinsetFamily section DistribLattice variable [DecidableEq α] -variable [DistribLattice α] [OrderBot α] [@DecidableRel α Disjoint] (s t u v : Finset α) +variable [DistribLattice α] [OrderBot α] [DecidableRel (α := α) Disjoint] (s t u v : Finset α) theorem disjSups_assoc : ∀ s t u : Finset α, s ○ t ○ u = s ○ (t ○ u) := by refine (associative_of_commutative_of_le inferInstance ?_).assoc @@ -547,7 +548,7 @@ lemma image_subset_diffs_left : b ∈ t → s.image (· \ b) ⊆ s \\ t := image lemma image_subset_diffs_right : a ∈ s → t.image (a \ ·) ⊆ s \\ t := image_subset_image₂_right lemma forall_mem_diffs {p : α → Prop} : (∀ c ∈ s \\ t, p c) ↔ ∀ a ∈ s, ∀ b ∈ t, p (a \ b) := - forall_image₂_iff + forall_mem_image₂ @[simp] lemma diffs_subset_iff : s \\ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a \ b ∈ u := image₂_subset_iff diff --git a/Mathlib/Data/Finsupp/Basic.lean b/Mathlib/Data/Finsupp/Basic.lean index efd119c83d79e..7c786c4ec0d7e 100644 --- a/Mathlib/Data/Finsupp/Basic.lean +++ b/Mathlib/Data/Finsupp/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.BigOperators.Finsupp import Mathlib.Algebra.Group.Action.Basic import Mathlib.Algebra.Module.Basic import Mathlib.Algebra.Regular.SMul +import Mathlib.Data.Finsupp.SMulWithZero import Mathlib.Data.Rat.BigOperators /-! @@ -1285,25 +1286,11 @@ end section -instance smulZeroClass [Zero M] [SMulZeroClass R M] : SMulZeroClass R (α →₀ M) where - smul a v := v.mapRange (a • ·) (smul_zero _) - smul_zero a := by - ext - apply smul_zero - /-! Throughout this section, some `Monoid` and `Semiring` arguments are specified with `{}` instead of `[]`. See note [implicit instance arguments]. -/ -@[simp, norm_cast] -theorem coe_smul [Zero M] [SMulZeroClass R M] (b : R) (v : α →₀ M) : ⇑(b • v) = b • ⇑v := - rfl - -theorem smul_apply [Zero M] [SMulZeroClass R M] (b : R) (v : α →₀ M) (a : α) : - (b • v) a = b • v a := - rfl - theorem _root_.IsSMulRegular.finsupp [Zero M] [SMulZeroClass R M] {k : R} (hk : IsSMulRegular M k) : IsSMulRegular (α →₀ M) k := fun _ _ h => ext fun i => hk (DFunLike.congr_fun h i) @@ -1314,34 +1301,14 @@ instance faithfulSMul [Nonempty α] [Zero M] [SMulZeroClass R M] [FaithfulSMul R let ⟨a⟩ := ‹Nonempty α› eq_of_smul_eq_smul fun m : M => by simpa using DFunLike.congr_fun (h (single a m)) a -instance instSMulWithZero [Zero R] [Zero M] [SMulWithZero R M] : SMulWithZero R (α →₀ M) where - zero_smul f := by ext i; exact zero_smul _ _ - variable (α M) -instance distribSMul [AddZeroClass M] [DistribSMul R M] : DistribSMul R (α →₀ M) where - smul := (· • ·) - smul_add _ _ _ := ext fun _ => smul_add _ _ _ - smul_zero _ := ext fun _ => smul_zero _ - instance distribMulAction [Monoid R] [AddMonoid M] [DistribMulAction R M] : DistribMulAction R (α →₀ M) := { Finsupp.distribSMul _ _ with one_smul := fun x => ext fun y => one_smul R (x y) mul_smul := fun r s x => ext fun y => mul_smul r s (x y) } -instance isScalarTower [Zero M] [SMulZeroClass R M] [SMulZeroClass S M] [SMul R S] - [IsScalarTower R S M] : IsScalarTower R S (α →₀ M) where - smul_assoc _ _ _ := ext fun _ => smul_assoc _ _ _ - -instance smulCommClass [Zero M] [SMulZeroClass R M] [SMulZeroClass S M] [SMulCommClass R S M] : - SMulCommClass R S (α →₀ M) where - smul_comm _ _ _ := ext fun _ => smul_comm _ _ _ - -instance isCentralScalar [Zero M] [SMulZeroClass R M] [SMulZeroClass Rᵐᵒᵖ M] [IsCentralScalar R M] : - IsCentralScalar R (α →₀ M) where - op_smul_eq_smul _ _ := ext fun _ => op_smul_eq_smul _ _ - instance module [Semiring R] [AddCommMonoid M] [Module R M] : Module R (α →₀ M) := { toDistribMulAction := Finsupp.distribMulAction α M zero_smul := fun _ => ext fun _ => zero_smul _ _ @@ -1349,11 +1316,6 @@ instance module [Semiring R] [AddCommMonoid M] [Module R M] : Module R (α → variable {α M} -theorem support_smul [AddMonoid M] [SMulZeroClass R M] {b : R} {g : α →₀ M} : - (b • g).support ⊆ g.support := fun a => by - simp only [smul_apply, mem_support_iff, Ne] - exact mt fun h => h.symm ▸ smul_zero _ - @[simp] theorem support_smul_eq [Semiring R] [AddCommMonoid M] [Module R M] [NoZeroSMulDivisors R M] {b : R} (hb : b ≠ 0) {g : α →₀ M} : (b • g).support = g.support := @@ -1376,25 +1338,11 @@ theorem mapDomain_smul {_ : Monoid R} [AddCommMonoid M] [DistribMulAction R M] { (v : α →₀ M) : mapDomain f (b • v) = b • mapDomain f v := mapDomain_mapRange _ _ _ _ (smul_add b) -@[simp] -theorem smul_single [Zero M] [SMulZeroClass R M] (c : R) (a : α) (b : M) : - c • Finsupp.single a b = Finsupp.single a (c • b) := - mapRange_single - -- Porting note: removed `simp` because `simpNF` can prove it. theorem smul_single' {_ : Semiring R} (c : R) (a : α) (b : R) : c • Finsupp.single a b = Finsupp.single a (c * b) := smul_single _ _ _ -theorem mapRange_smul {_ : Monoid R} [AddMonoid M] [DistribMulAction R M] [AddMonoid N] - [DistribMulAction R N] {f : M → N} {hf : f 0 = 0} (c : R) (v : α →₀ M) - (hsmul : ∀ x, f (c • x) = c • f x) : mapRange f hf (c • v) = c • mapRange f hf v := by - erw [← mapRange_comp] - · have : f ∘ (c • ·) = (c • ·) ∘ f := funext hsmul - simp_rw [this] - apply mapRange_comp - simp only [Function.comp_apply, smul_zero, hf] - theorem smul_single_one [Semiring R] (a : α) (b : R) : b • single a (1 : R) = single a b := by rw [smul_single, smul_eq_mul, mul_one] @@ -1427,11 +1375,10 @@ theorem sum_smul_index_addMonoidHom [AddMonoid M] [AddCommMonoid N] [DistribSMul {b : R} {h : α → M →+ N} : ((b • g).sum fun a => h a) = g.sum fun i c => h i (b • c) := sum_mapRange_index fun i => (h i).map_zero -instance noZeroSMulDivisors [Semiring R] [AddCommMonoid M] [Module R M] {ι : Type*} +instance noZeroSMulDivisors [Zero R] [Zero M] [SMulZeroClass R M] {ι : Type*} [NoZeroSMulDivisors R M] : NoZeroSMulDivisors R (ι →₀ M) := - ⟨fun h => - or_iff_not_imp_left.mpr fun hc => - Finsupp.ext fun i => (smul_eq_zero.mp (DFunLike.ext_iff.mp h i)).resolve_left hc⟩ + ⟨fun h => or_iff_not_imp_left.mpr fun hc => Finsupp.ext fun i => + (eq_zero_or_eq_zero_of_smul_eq_zero (DFunLike.ext_iff.mp h i)).resolve_left hc⟩ section DistribMulActionSemiHom variable [Monoid R] [AddMonoid M] [AddMonoid N] [DistribMulAction R M] [DistribMulAction R N] @@ -1702,4 +1649,4 @@ end Sigma end Finsupp -set_option linter.style.longFile 1900 +set_option linter.style.longFile 1700 diff --git a/Mathlib/Data/Finsupp/Lex.lean b/Mathlib/Data/Finsupp/Lex.lean index 6b2a45dd8483b..87e567ec57773 100644 --- a/Mathlib/Data/Finsupp/Lex.lean +++ b/Mathlib/Data/Finsupp/Lex.lean @@ -75,6 +75,26 @@ instance Lex.linearOrder [LinearOrder N] : LinearOrder (Lex (α →₀ N)) where le := (· ≤ ·) __ := LinearOrder.lift' (toLex ∘ toDFinsupp ∘ ofLex) finsuppEquivDFinsupp.injective +theorem Lex.single_strictAnti : StrictAnti (fun (a : α) ↦ toLex (single a 1)) := by + intro a b h + simp only [LT.lt, Finsupp.lex_def] + simp only [ofLex_toLex, Nat.lt_eq] + use a + constructor + · intro d hd + simp only [Finsupp.single_eq_of_ne (ne_of_lt hd).symm, + Finsupp.single_eq_of_ne (ne_of_gt (lt_trans hd h))] + · simp only [single_eq_same, single_eq_of_ne (ne_of_lt h).symm, zero_lt_one] + +theorem Lex.single_lt_iff {a b : α} : toLex (single b 1) < toLex (single a 1) ↔ a < b := + Lex.single_strictAnti.lt_iff_lt + +theorem Lex.single_le_iff {a b : α} : toLex (single b 1) ≤ toLex (single a 1) ↔ a ≤ b := + Lex.single_strictAnti.le_iff_le + +theorem Lex.single_antitone : Antitone (fun (a : α) ↦ toLex (single a 1)) := + Lex.single_strictAnti.antitone + variable [PartialOrder N] theorem toLex_monotone : Monotone (@toLex (α →₀ N)) := diff --git a/Mathlib/Data/Finsupp/MonomialOrder.lean b/Mathlib/Data/Finsupp/MonomialOrder.lean index 431fcb7d3ce34..788df94797c35 100644 --- a/Mathlib/Data/Finsupp/MonomialOrder.lean +++ b/Mathlib/Data/Finsupp/MonomialOrder.lean @@ -135,7 +135,6 @@ example : toLex (Finsupp.single 1 1) < toLex (Finsupp.single 0 1) := by example : toLex (Finsupp.single 1 1) < toLex (Finsupp.single 0 2) := by use 0; simp - variable {σ : Type*} [LinearOrder σ] /-- The lexicographic order on `σ →₀ ℕ`, as a `MonomialOrder` -/ diff --git a/Mathlib/Data/Finsupp/MonomialOrder/DegLex.lean b/Mathlib/Data/Finsupp/MonomialOrder/DegLex.lean new file mode 100644 index 0000000000000..0deee8bfefe7c --- /dev/null +++ b/Mathlib/Data/Finsupp/MonomialOrder/DegLex.lean @@ -0,0 +1,258 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ + +import Mathlib.Data.Finsupp.MonomialOrder +import Mathlib.Data.Finsupp.Weight +import Mathlib.Logic.Equiv.TransferInstance + +/-! Homogeneous lexicographic monomial ordering + +* `MonomialOrder.degLex`: a variant of the lexicographic ordering that first compares degrees. +For this, `σ` needs to be embedded with an ordering relation which satisfies `WellFoundedGT σ`. +(This last property is automatic when `σ` is finite). + +The type synonym is `DegLex (σ →₀ ℕ)` and the two lemmas `MonomialOrder.degLex_le_iff` +and `MonomialOrder.degLex_lt_iff` rewrite the ordering as comparisons in the type `Lex (σ →₀ ℕ)`. + +## References + +* [Cox, Little and O'Shea, *Ideals, varieties, and algorithms*][coxlittleoshea1997] +* [Becker and Weispfenning, *Gröbner bases*][Becker-Weispfenning1993] + +-/ + +section degLex + +/-- A type synonym to equip a type with its lexicographic order sorted by degrees. -/ +def DegLex (α : Type*) := α + +variable {α : Type*} + +/-- `toDegLex` is the identity function to the `DegLex` of a type. -/ +@[match_pattern] def toDegLex : α ≃ DegLex α := Equiv.refl _ + +theorem toDegLex_injective : Function.Injective (toDegLex (α := α)) := fun _ _ ↦ _root_.id + +theorem toDegLex_inj {a b : α} : toDegLex a = toDegLex b ↔ a = b := Iff.rfl + +/-- `ofDegLex` is the identity function from the `DegLex` of a type. -/ +@[match_pattern] def ofDegLex : DegLex α ≃ α := Equiv.refl _ + +theorem ofDegLex_injective : Function.Injective (ofDegLex (α := α)) := fun _ _ ↦ _root_.id + +theorem ofDegLex_inj {a b : DegLex α} : ofDegLex a = ofDegLex b ↔ a = b := Iff.rfl + +@[simp] theorem ofDegLex_symm_eq : (@ofDegLex α).symm = toDegLex := rfl + +@[simp] theorem toDegLex_symm_eq : (@toDegLex α).symm = ofDegLex := rfl + +@[simp] theorem ofDegLex_toDegLex (a : α) : ofDegLex (toDegLex a) = a := rfl + +@[simp] theorem toDegLex_ofDegLex (a : DegLex α) : toDegLex (ofDegLex a) = a := rfl + +/-- A recursor for `DegLex`. Use as `induction x`. -/ +@[elab_as_elim, induction_eliminator, cases_eliminator] +protected def DegLex.rec {β : DegLex α → Sort*} (h : ∀ a, β (toDegLex a)) : + ∀ a, β a := fun a => h (ofDegLex a) + +@[simp] lemma DegLex.forall_iff {p : DegLex α → Prop} : (∀ a, p a) ↔ ∀ a, p (toDegLex a) := Iff.rfl +@[simp] lemma DegLex.exists_iff {p : DegLex α → Prop} : (∃ a, p a) ↔ ∃ a, p (toDegLex a) := Iff.rfl + +noncomputable instance [AddCommMonoid α] : + AddCommMonoid (DegLex α) := ofDegLex.addCommMonoid + +theorem toDegLex_add [AddCommMonoid α] (a b : α) : + toDegLex (a + b) = toDegLex a + toDegLex b := rfl + +theorem ofDegLex_add [AddCommMonoid α] (a b : DegLex α) : + ofDegLex (a + b) = ofDegLex a + ofDegLex b := rfl + +namespace Finsupp + +/-- `Finsupp.DegLex r s` is the homogeneous lexicographic order on `α →₀ M`, +where `α` is ordered by `r` and `M` is ordered by `s`. +The type synonym `DegLex (α →₀ M)` has an order given by `Finsupp.DegLex (· < ·) (· < ·)`. -/ +protected def DegLex (r : α → α → Prop) (s : ℕ → ℕ → Prop) : + (α →₀ ℕ) → (α →₀ ℕ) → Prop := + (Prod.Lex s (Finsupp.Lex r s)) on (fun x ↦ (x.degree, x)) + +theorem degLex_def {r : α → α → Prop} {s : ℕ → ℕ → Prop} {a b : α →₀ ℕ} : + Finsupp.DegLex r s a b ↔ Prod.Lex s (Finsupp.Lex r s) (a.degree, a) (b.degree, b) := + Iff.rfl + +namespace DegLex + +theorem wellFounded + {r : α → α → Prop} [IsTrichotomous α r] (hr : WellFounded (Function.swap r)) + {s : ℕ → ℕ → Prop} (hs : WellFounded s) (hs0 : ∀ ⦃n⦄, ¬ s n 0) : + WellFounded (Finsupp.DegLex r s) := by + have wft := WellFounded.prod_lex hs (Finsupp.Lex.wellFounded' hs0 hs hr) + rw [← Set.wellFoundedOn_univ] at wft + unfold Finsupp.DegLex + rw [← Set.wellFoundedOn_range] + exact Set.WellFoundedOn.mono wft (le_refl _) (fun _ _ ↦ trivial) + +instance [LT α] : LT (DegLex (α →₀ ℕ)) := + ⟨fun f g ↦ Finsupp.DegLex (· < ·) (· < ·) (ofDegLex f) (ofDegLex g)⟩ + +theorem lt_def [LT α] {a b : DegLex (α →₀ ℕ)} : + a < b ↔ (toLex ((ofDegLex a).degree, toLex (ofDegLex a))) < + (toLex ((ofDegLex b).degree, toLex (ofDegLex b))) := + Iff.rfl + +theorem lt_iff [LT α] {a b : DegLex (α →₀ ℕ)} : + a < b ↔ (ofDegLex a).degree < (ofDegLex b).degree ∨ + (((ofDegLex a).degree = (ofDegLex b).degree) ∧ toLex (ofDegLex a) < toLex (ofDegLex b)) := by + simp only [lt_def, Prod.Lex.lt_iff] + +variable [LinearOrder α] + +instance isStrictOrder : IsStrictOrder (DegLex (α →₀ ℕ)) (· < ·) where + irrefl := fun a ↦ by simp [lt_def] + trans := by + intro a b c hab hbc + simp only [lt_iff] at hab hbc ⊢ + rcases hab with (hab | hab) + · rcases hbc with (hbc | hbc) + · left; exact lt_trans hab hbc + · left; exact lt_of_lt_of_eq hab hbc.1 + · rcases hbc with (hbc | hbc) + · left; exact lt_of_eq_of_lt hab.1 hbc + · right; exact ⟨Eq.trans hab.1 hbc.1, lt_trans hab.2 hbc.2⟩ + +/-- The linear order on `Finsupp`s obtained by the homogeneous lexicographic ordering. -/ +instance : LinearOrder (DegLex (α →₀ ℕ)) := + LinearOrder.lift' + (fun (f : DegLex (α →₀ ℕ)) ↦ toLex ((ofDegLex f).degree, toLex (ofDegLex f))) + (fun f g ↦ by simp) + +theorem le_iff {x y : DegLex (α →₀ ℕ)} : + x ≤ y ↔ (ofDegLex x).degree < (ofDegLex y).degree ∨ + (ofDegLex x).degree = (ofDegLex y).degree ∧ toLex (ofDegLex x) ≤ toLex (ofDegLex y) := by + simp only [le_iff_eq_or_lt, lt_iff, EmbeddingLike.apply_eq_iff_eq] + by_cases h : x = y + · simp [h] + · by_cases k : (ofDegLex x).degree < (ofDegLex y).degree + · simp [k] + · simp only [h, k, false_or] + +noncomputable instance : OrderedCancelAddCommMonoid (DegLex (α →₀ ℕ)) where + le_of_add_le_add_left a b c h := by + rw [le_iff] at h ⊢ + simpa only [ofDegLex_add, degree_add, add_lt_add_iff_left, add_right_inj, toLex_add, + add_le_add_iff_left] using h + add_le_add_left a b h c := by + rw [le_iff] at h ⊢ + simpa [ofDegLex_add, degree_add] using h + +/-- The linear order on `Finsupp`s obtained by the homogeneous lexicographic ordering. -/ +noncomputable instance : + LinearOrderedCancelAddCommMonoid (DegLex (α →₀ ℕ)) where + le_total := instLinearOrderDegLexNat.le_total + decidableLE := instLinearOrderDegLexNat.decidableLE + compare_eq_compareOfLessAndEq := instLinearOrderDegLexNat.compare_eq_compareOfLessAndEq + +theorem single_strictAnti : StrictAnti (fun (a : α) ↦ toDegLex (single a 1)) := by + intro _ _ h + simp only [lt_iff, ofDegLex_toDegLex, degree_single, lt_self_iff_false, Lex.single_lt_iff, h, + and_self, or_true] + +theorem single_antitone : Antitone (fun (a : α) ↦ toDegLex (single a 1)) := + single_strictAnti.antitone + +theorem single_lt_iff {a b : α} : + toDegLex (Finsupp.single b 1) < toDegLex (Finsupp.single a 1) ↔ a < b := + single_strictAnti.lt_iff_lt + +theorem single_le_iff {a b : α} : + toDegLex (Finsupp.single b 1) ≤ toDegLex (Finsupp.single a 1) ↔ a ≤ b := + single_strictAnti.le_iff_le + +theorem monotone_degree : + Monotone (fun (x : DegLex (α →₀ ℕ)) ↦ (ofDegLex x).degree) := by + intro x y + rw [le_iff] + rintro (h | h) + · apply le_of_lt h + · apply le_of_eq h.1 + +instance orderBot : OrderBot (DegLex (α →₀ ℕ)) where + bot := toDegLex (0 : α →₀ ℕ) + bot_le x := by + simp only [le_iff, ofDegLex_toDegLex, toLex_zero, degree_zero] + rcases eq_zero_or_pos (ofDegLex x).degree with (h | h) + · simp only [h, lt_self_iff_false, true_and, false_or, ge_iff_le] + exact bot_le + · simp [h] + +instance wellFoundedLT [WellFoundedGT α] : + WellFoundedLT (DegLex (α →₀ ℕ)) := + ⟨wellFounded wellFounded_gt wellFounded_lt fun n ↦ (zero_le n).not_lt⟩ + +end DegLex + +end Finsupp + +namespace MonomialOrder + +open Finsupp + +variable {σ : Type*} [LinearOrder σ] [WellFoundedGT σ] + +/-- The deg-lexicographic order on `σ →₀ ℕ`, as a `MonomialOrder` -/ +noncomputable def degLex : + MonomialOrder σ where + syn := DegLex (σ →₀ ℕ) + toSyn := { toEquiv := toDegLex, map_add' := toDegLex_add } + toSyn_monotone a b h := by + simp only [AddEquiv.coe_mk, DegLex.le_iff, ofDegLex_toDegLex] + by_cases ha : a.degree < b.degree + · exact Or.inl ha + · refine Or.inr ⟨le_antisymm ?_ (not_lt.mp ha), toLex_monotone h⟩ + rw [← add_tsub_cancel_of_le h, degree_add] + exact Nat.le_add_right a.degree (b - a).degree + +theorem degLex_le_iff {a b : σ →₀ ℕ} : + a ≼[degLex] b ↔ toDegLex a ≤ toDegLex b := + Iff.rfl + +theorem degLex_lt_iff {a b : σ →₀ ℕ} : + a ≺[degLex] b ↔ toDegLex a < toDegLex b := + Iff.rfl + +theorem degLex_single_le_iff {a b : σ} : + single a 1 ≼[degLex] single b 1 ↔ b ≤ a := by + rw [MonomialOrder.degLex_le_iff, DegLex.single_le_iff] + +theorem degLex_single_lt_iff {a b : σ} : + single a 1 ≺[degLex] single b 1 ↔ b < a := by + rw [MonomialOrder.degLex_lt_iff, DegLex.single_lt_iff] + +end MonomialOrder + +section Examples + +open Finsupp MonomialOrder DegLex + +/-- for the deg-lexicographic ordering, X 1 < X 0 -/ +example : single (1 : Fin 2) 1 ≺[degLex] single 0 1 := by + rw [degLex_lt_iff, single_lt_iff] + exact Nat.one_pos + +/-- for the deg-lexicographic ordering, X 0 * X 1 < X 0 ^ 2 -/ +example : (single 0 1 + single 1 1) ≺[degLex] single (0 : Fin 2) 2 := by + simp only [degLex_lt_iff, lt_iff, ofDegLex_toDegLex, degree_add, + degree_single, Nat.reduceAdd, lt_self_iff_false, true_and, false_or] + use 0 + simp + +/-- for the deg-lexicographic ordering, X 0 < X 1 ^ 2 -/ +example : single (0 : Fin 2) 1 ≺[degLex] single 1 2 := by + simp [degLex_lt_iff, lt_iff] + +end Examples + +end degLex diff --git a/Mathlib/Data/Finsupp/Order.lean b/Mathlib/Data/Finsupp/Order.lean index b06f454769ac2..ad9bfbd4b5485 100644 --- a/Mathlib/Data/Finsupp/Order.lean +++ b/Mathlib/Data/Finsupp/Order.lean @@ -322,6 +322,10 @@ theorem add_sub_single_one {a : ι} {u u' : ι →₀ ℕ} (h : u' a ≠ 0) : u + (u' - single a 1) = u + u' - single a 1 := (add_tsub_assoc_of_le (single_le_iff.mpr <| Nat.one_le_iff_ne_zero.mpr h) _).symm +lemma sub_add_single_one_cancel {u : ι →₀ ℕ} {i : ι} (h : u i ≠ 0) : + u - single i 1 + single i 1 = u := by + rw [sub_single_one_add h, add_tsub_cancel_right] + end Nat end Finsupp diff --git a/Mathlib/Data/Finsupp/SMulWithZero.lean b/Mathlib/Data/Finsupp/SMulWithZero.lean new file mode 100644 index 0000000000000..e7e1adc5d920c --- /dev/null +++ b/Mathlib/Data/Finsupp/SMulWithZero.lean @@ -0,0 +1,102 @@ +/- +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, Kim Morrison +-/ +import Mathlib.Algebra.Group.Action.Pi +import Mathlib.Algebra.SMulWithZero +import Mathlib.Data.Finsupp.Defs + +/-! +# Scalar multiplication on `Finsupp` + +This file defines the pointwise scalar multiplication on `Finsupp`, assuming it preserves zero. + +## Main declarations + +* `Finsupp.smulZeroClass`: if the action of `R` on `M` preserves `0`, then it acts on `α →₀ M` + +## Implementation notes + +This file is intermediate between `Finsupp.Defs` and `Finsupp.Module` in that it covers scalar +multiplication but does not rely on the definition of `Module`. Scalar multiplication is needed to +supply the `nsmul` (and `zsmul`) fields of (semi)ring structures which are fundamental for e.g. +`Polynomial`, so we want to keep the imports requied for the `Finsupp.smulZeroClass` instance +reasonably light. + +This file is a `noncomputable theory` and uses classical logic throughout. +-/ + +assert_not_exists Module + +noncomputable section + +open Finset Function + +variable {α β γ ι M M' N P G H R S : Type*} + +namespace Finsupp + +instance smulZeroClass [Zero M] [SMulZeroClass R M] : SMulZeroClass R (α →₀ M) where + smul a v := v.mapRange (a • ·) (smul_zero _) + smul_zero a := by + ext + apply smul_zero + +/-! +Throughout this section, some `Monoid` and `Semiring` arguments are specified with `{}` instead of +`[]`. See note [implicit instance arguments]. +-/ + +@[simp, norm_cast] +theorem coe_smul [Zero M] [SMulZeroClass R M] (b : R) (v : α →₀ M) : ⇑(b • v) = b • ⇑v := + rfl + +theorem smul_apply [Zero M] [SMulZeroClass R M] (b : R) (v : α →₀ M) (a : α) : + (b • v) a = b • v a := + rfl + +instance instSMulWithZero [Zero R] [Zero M] [SMulWithZero R M] : SMulWithZero R (α →₀ M) where + zero_smul f := by ext i; exact zero_smul _ _ + +variable (α M) + +instance distribSMul [AddZeroClass M] [DistribSMul R M] : DistribSMul R (α →₀ M) where + smul := (· • ·) + smul_add _ _ _ := ext fun _ => smul_add _ _ _ + smul_zero _ := ext fun _ => smul_zero _ + +instance isScalarTower [Zero M] [SMulZeroClass R M] [SMulZeroClass S M] [SMul R S] + [IsScalarTower R S M] : IsScalarTower R S (α →₀ M) where + smul_assoc _ _ _ := ext fun _ => smul_assoc _ _ _ + +instance smulCommClass [Zero M] [SMulZeroClass R M] [SMulZeroClass S M] [SMulCommClass R S M] : + SMulCommClass R S (α →₀ M) where + smul_comm _ _ _ := ext fun _ => smul_comm _ _ _ + +instance isCentralScalar [Zero M] [SMulZeroClass R M] [SMulZeroClass Rᵐᵒᵖ M] [IsCentralScalar R M] : + IsCentralScalar R (α →₀ M) where + op_smul_eq_smul _ _ := ext fun _ => op_smul_eq_smul _ _ + +variable {α M} + +theorem support_smul [AddMonoid M] [SMulZeroClass R M] {b : R} {g : α →₀ M} : + (b • g).support ⊆ g.support := fun a => by + simp only [smul_apply, mem_support_iff, Ne] + exact mt fun h => h.symm ▸ smul_zero _ + +@[simp] +theorem smul_single [Zero M] [SMulZeroClass R M] (c : R) (a : α) (b : M) : + c • Finsupp.single a b = Finsupp.single a (c • b) := + mapRange_single + +theorem mapRange_smul {_ : Monoid R} [AddMonoid M] [DistribMulAction R M] [AddMonoid N] + [DistribMulAction R N] {f : M → N} {hf : f 0 = 0} (c : R) (v : α →₀ M) + (hsmul : ∀ x, f (c • x) = c • f x) : mapRange f hf (c • v) = c • mapRange f hf v := by + erw [← mapRange_comp] + · have : f ∘ (c • ·) = (c • ·) ∘ f := funext hsmul + simp_rw [this] + apply mapRange_comp + simp only [Function.comp_apply, smul_zero, hf] + +end Finsupp diff --git a/Mathlib/Data/Finsupp/Weight.lean b/Mathlib/Data/Finsupp/Weight.lean index 2278beedc1aec..36ec2f64e9d94 100644 --- a/Mathlib/Data/Finsupp/Weight.lean +++ b/Mathlib/Data/Finsupp/Weight.lean @@ -105,6 +105,13 @@ theorem NonTorsionWeight.ne_zero [NonTorsionWeight w] (s : σ) : apply Nat.zero_ne_one.symm exact NonTorsionWeight.eq_zero_of_smul_eq_zero h +variable {w} in +lemma weight_sub_single_add {f : σ →₀ ℕ} {i : σ} (hi : f i ≠ 0) : + (f - single i 1).weight w + w i = f.weight w := by + conv_rhs => rw [← sub_add_single_one_cancel hi, weight_apply] + rw [sum_add_index', sum_single_index, one_smul, weight_apply] + exacts [zero_smul .., fun _ ↦ zero_smul .., fun _ _ _ ↦ add_smul ..] + end AddCommMonoid section OrderedAddCommMonoid @@ -195,6 +202,20 @@ def degree (d : σ →₀ ℕ) := ∑ i ∈ d.support, d i @[deprecated degree (since := "2024-07-20")] alias _root_.MvPolynomial.degree := degree +@[simp] +theorem degree_add (a b : σ →₀ ℕ) : (a + b).degree = a.degree + b.degree := + sum_add_index' (h := fun _ ↦ id) (congrFun rfl) fun _ _ ↦ congrFun rfl + +@[simp] +theorem degree_single (a : σ) (m : ℕ) : (Finsupp.single a m).degree = m := by + rw [degree, Finset.sum_eq_single a] + · simp only [single_eq_same] + · intro b _ hba + exact single_eq_of_ne hba.symm + · intro ha + simp only [mem_support_iff, single_eq_same, ne_eq, Decidable.not_not] at ha + rw [single_eq_same, ha] + lemma degree_eq_zero_iff (d : σ →₀ ℕ) : degree d = 0 ↔ d = 0 := by simp only [degree, Finset.sum_eq_zero_iff, Finsupp.mem_support_iff, ne_eq, Decidable.not_imp_self, DFunLike.ext_iff, Finsupp.coe_zero, Pi.zero_apply] diff --git a/Mathlib/Data/Fintype/BigOperators.lean b/Mathlib/Data/Fintype/BigOperators.lean index 6c8241d4dd465..0825cf4335415 100644 --- a/Mathlib/Data/Fintype/BigOperators.lean +++ b/Mathlib/Data/Fintype/BigOperators.lean @@ -172,7 +172,8 @@ theorem Fintype.card_fun [DecidableEq α] [Fintype α] [Fintype β] : simp @[simp] -theorem card_vector [Fintype α] (n : ℕ) : Fintype.card (Vector α n) = Fintype.card α ^ n := by +theorem card_vector [Fintype α] (n : ℕ) : + Fintype.card (Mathlib.Vector α n) = Fintype.card α ^ n := by rw [Fintype.ofEquiv_card]; simp /-- It is equivalent to compute the product of a function over `Fin n` or `Finset.range n`. -/ diff --git a/Mathlib/Data/Fintype/Card.lean b/Mathlib/Data/Fintype/Card.lean index 59e57330eb779..d9cf21d019a1f 100644 --- a/Mathlib/Data/Fintype/Card.lean +++ b/Mathlib/Data/Fintype/Card.lean @@ -706,15 +706,29 @@ theorem set_fintype_card_eq_univ_iff [Fintype α] (s : Set α) [Fintype s] : namespace Function.Embedding /-- An embedding from a `Fintype` to itself can be promoted to an equivalence. -/ -noncomputable def equivOfFintypeSelfEmbedding [Finite α] (e : α ↪ α) : α ≃ α := +noncomputable def equivOfFiniteSelfEmbedding [Finite α] (e : α ↪ α) : α ≃ α := Equiv.ofBijective e e.2.bijective_of_finite +@[deprecated (since := "2024-12-05")] +alias equivOfFintypeSelfEmbedding := equivOfFiniteSelfEmbedding + @[simp] -theorem equiv_of_fintype_self_embedding_to_embedding [Finite α] (e : α ↪ α) : - e.equivOfFintypeSelfEmbedding.toEmbedding = e := by +theorem toEmbedding_equivOfFiniteSelfEmbedding [Finite α] (e : α ↪ α) : + e.equivOfFiniteSelfEmbedding.toEmbedding = e := by ext rfl +@[deprecated (since := "2024-12-05")] +alias equiv_of_fintype_self_embedding_to_embedding := toEmbedding_equivOfFiniteSelfEmbedding + +/-- On a finite type, equivalence between the self-embeddings and the bijections. -/ +@[simps] noncomputable def _root_.Equiv.embeddingEquivOfFinite (α : Type*) [Finite α] : + (α ↪ α) ≃ (α ≃ α) where + toFun e := e.equivOfFiniteSelfEmbedding + invFun e := e.toEmbedding + left_inv e := rfl + right_inv e := by ext; rfl + /-- If `‖β‖ < ‖α‖` there are no embeddings `α ↪ β`. This is a formulation of the pigeonhole principle. @@ -750,7 +764,7 @@ end Function.Embedding @[simp] theorem Finset.univ_map_embedding {α : Type*} [Fintype α] (e : α ↪ α) : univ.map e = univ := by - rw [← e.equiv_of_fintype_self_embedding_to_embedding, univ_map_equiv_to_embedding] + rw [← e.toEmbedding_equivOfFiniteSelfEmbedding, univ_map_equiv_to_embedding] namespace Fintype @@ -1100,7 +1114,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 [klift, Fin.valEmbedding_apply, Fin.val_mk, List.pmap_eq_map, List.map_id'] use l.map (List.map (Fintype.equivFin α).symm) constructor · -- length diff --git a/Mathlib/Data/Fintype/Fin.lean b/Mathlib/Data/Fintype/Fin.lean index 8744f61e2f3ae..96b7ea32bd858 100644 --- a/Mathlib/Data/Fintype/Fin.lean +++ b/Mathlib/Data/Fintype/Fin.lean @@ -61,7 +61,7 @@ theorem card_filter_univ_succ' (p : Fin (n + 1) → Prop) [DecidablePred p] : #{x | p x} = ite (p 0) 1 0 + #{x | p (.succ x)}:= by rw [card_filter_univ_succ]; split_ifs <;> simp [add_comm] -theorem card_filter_univ_eq_vector_get_eq_count [DecidableEq α] (a : α) (v : Vector α n) : +theorem card_filter_univ_eq_vector_get_eq_count [DecidableEq α] (a : α) (v : Mathlib.Vector α n) : #{i | v.get i = a} = v.toList.count a := by induction' v with n x xs hxs · simp diff --git a/Mathlib/Data/Fintype/Vector.lean b/Mathlib/Data/Fintype/Vector.lean index 2e94be07c8dbd..9b833c039d387 100644 --- a/Mathlib/Data/Fintype/Vector.lean +++ b/Mathlib/Data/Fintype/Vector.lean @@ -14,7 +14,7 @@ open Mathlib (Vector) variable {α : Type*} -instance Vector.fintype [Fintype α] {n : ℕ} : Fintype (Vector α n) := +instance Vector.fintype [Fintype α] {n : ℕ} : Fintype (Mathlib.Vector α n) := Fintype.ofEquiv _ (Equiv.vectorEquivFin _ _).symm instance [DecidableEq α] [Fintype α] {n : ℕ} : Fintype (Sym.Sym' α n) := by diff --git a/Mathlib/Data/Int/Cast/Lemmas.lean b/Mathlib/Data/Int/Cast/Lemmas.lean index d887d52523d54..5610ebe757d4d 100644 --- a/Mathlib/Data/Int/Cast/Lemmas.lean +++ b/Mathlib/Data/Int/Cast/Lemmas.lean @@ -366,25 +366,3 @@ end NonAssocRing @[simp] theorem Int.castRingHom_int : Int.castRingHom ℤ = RingHom.id ℤ := (RingHom.id ℤ).eq_intCast'.symm - -namespace Pi - -variable {π : ι → Type*} [∀ i, IntCast (π i)] - -instance instIntCast : IntCast (∀ i, π i) where intCast n _ := n - -theorem intCast_apply (n : ℤ) (i : ι) : (n : ∀ i, π i) i = n := - rfl - -@[simp] -theorem intCast_def (n : ℤ) : (n : ∀ i, π i) = fun _ => ↑n := - rfl - -@[deprecated (since := "2024-04-05")] alias int_apply := intCast_apply -@[deprecated (since := "2024-04-05")] alias coe_int := intCast_def - -end Pi - -theorem Sum.elim_intCast_intCast {α β γ : Type*} [IntCast γ] (n : ℤ) : - Sum.elim (n : α → γ) (n : β → γ) = n := - Sum.elim_lam_const_lam_const (γ := γ) n diff --git a/Mathlib/Data/Int/Cast/Pi.lean b/Mathlib/Data/Int/Cast/Pi.lean new file mode 100644 index 0000000000000..cfdb7b2de7b54 --- /dev/null +++ b/Mathlib/Data/Int/Cast/Pi.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2017 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro +-/ +import Batteries.Tactic.Alias +import Mathlib.Data.Int.Notation +import Mathlib.Tactic.TypeStar +import Mathlib.Util.AssertExists + +/-! +# Cast of integers to function types + +This file provides a (pointwise) cast from `ℤ` to function types. + +## Main declarations + +* `Pi.instIntCast`: map `n : ℤ` to the constant function `n : ∀ i, π i` +-/ + +assert_not_exists OrderedCommMonoid +assert_not_exists RingHom + +namespace Pi + +variable {ι : Type*} {π : ι → Type*} [∀ i, IntCast (π i)] + +instance instIntCast : IntCast (∀ i, π i) where intCast n _ := n + +theorem intCast_apply (n : ℤ) (i : ι) : (n : ∀ i, π i) i = n := + rfl + +@[simp] +theorem intCast_def (n : ℤ) : (n : ∀ i, π i) = fun _ => ↑n := + rfl + +@[deprecated (since := "2024-04-05")] alias int_apply := intCast_apply +@[deprecated (since := "2024-04-05")] alias coe_int := intCast_def + +end Pi + +theorem Sum.elim_intCast_intCast {α β γ : Type*} [IntCast γ] (n : ℤ) : + Sum.elim (n : α → γ) (n : β → γ) = n := + Sum.elim_lam_const_lam_const (γ := γ) n diff --git a/Mathlib/Data/Int/CharZero.lean b/Mathlib/Data/Int/CharZero.lean index 11a1e6a858d9a..49a66742d5cd6 100644 --- a/Mathlib/Data/Int/CharZero.lean +++ b/Mathlib/Data/Int/CharZero.lean @@ -6,6 +6,7 @@ Authors: Mario Carneiro import Mathlib.Algebra.Group.Support import Mathlib.Data.Int.Cast.Field import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Data.Int.Cast.Pi /-! # Injectivity of `Int.Cast` into characteristic zero rings and fields. diff --git a/Mathlib/Data/Int/Defs.lean b/Mathlib/Data/Int/Defs.lean index 9fd2c581ce8e9..081c427a4817b 100644 --- a/Mathlib/Data/Int/Defs.lean +++ b/Mathlib/Data/Int/Defs.lean @@ -268,9 +268,9 @@ end inductionOn' /-- Inductively define a function on `ℤ` by defining it on `ℕ` and extending it from `n` to `-n`. -/ @[elab_as_elim] protected def negInduction {C : ℤ → Sort*} (nat : ∀ n : ℕ, C n) - (neg : ∀ n : ℕ, C n → C (-n)) : ∀ n : ℤ, C n + (neg : (∀ n : ℕ, C n) → ∀ n : ℕ, C (-n)) : ∀ n : ℤ, C n | .ofNat n => nat n - | .negSucc n => neg _ <| nat <| n + 1 + | .negSucc n => neg nat <| n + 1 /-- See `Int.inductionOn'` for an induction in both directions. -/ protected lemma le_induction {P : ℤ → Prop} {m : ℤ} (h0 : P m) @@ -348,6 +348,11 @@ lemma natAbs_sq (x : ℤ) : (x.natAbs : ℤ) ^ 2 = x ^ 2 := by alias natAbs_pow_two := natAbs_sq +theorem sign_mul_self_eq_natAbs : ∀ a : Int, sign a * a = natAbs a + | 0 => rfl + | Nat.succ _ => Int.one_mul _ + | -[_+1] => (Int.neg_eq_neg_one_mul _).symm + /-! ### `/` -/ @[simp, norm_cast] lemma natCast_div (m n : ℕ) : ((m / n : ℕ) : ℤ) = m / n := rfl diff --git a/Mathlib/Data/Int/Lemmas.lean b/Mathlib/Data/Int/Lemmas.lean index 42c4167321de5..f98d34103dd0d 100644 --- a/Mathlib/Data/Int/Lemmas.lean +++ b/Mathlib/Data/Int/Lemmas.lean @@ -133,4 +133,16 @@ theorem div2_bit (b n) : div2 (bit b n) = n := by @[deprecated (since := "2024-04-02")] alias abs_coe_nat := abs_natCast @[deprecated (since := "2024-04-02")] alias coe_nat_nonpos_iff := natCast_nonpos_iff +/-- Like `Int.ediv_emod_unique`, but permitting negative `b`. -/ +theorem ediv_emod_unique' {a b r q : Int} (h : b ≠ 0) : + a / b = q ∧ a % b = r ↔ r + b * q = a ∧ 0 ≤ r ∧ r < |b| := by + constructor + · intro ⟨rfl, rfl⟩ + exact ⟨emod_add_ediv a b, emod_nonneg _ h, emod_lt _ h⟩ + · intro ⟨rfl, hz, hb⟩ + constructor + · rw [Int.add_mul_ediv_left r q h, ediv_eq_zero_of_lt_abs hz hb] + simp [Int.zero_add] + · rw [add_mul_emod_self_left, ← emod_abs, emod_eq_of_lt hz hb] + end Int diff --git a/Mathlib/Data/List/Basic.lean b/Mathlib/Data/List/Basic.lean index 3f51c9f665d12..6b8c7c19967e6 100644 --- a/Mathlib/Data/List/Basic.lean +++ b/Mathlib/Data/List/Basic.lean @@ -329,7 +329,7 @@ theorem getLast_replicate_succ (m : ℕ) (a : α) : /-- If the last element of `l` does not satisfy `p`, then it is also the last element of `l.filter p`. -/ -lemma getLast_filter {p : α → Bool} : +lemma getLast_filter' {p : α → Bool} : ∀ (l : List α) (hlp : l.filter p ≠ []), p (l.getLast (hlp <| ·.symm ▸ rfl)) = true → (l.filter p).getLast hlp = l.getLast (hlp <| ·.symm ▸ rfl) | [a], h, h' => by rw [List.getLast_singleton'] at h'; simp [List.filter_cons, h'] @@ -338,10 +338,10 @@ lemma getLast_filter {p : α → Bool} : simp only [List.filter_cons (x := a)] at h ⊢ obtain ha | ha := Bool.eq_false_or_eq_true (p a) · simp only [ha, ite_true] - rw [getLast_cons, getLast_filter (b :: as) _ h'] + rw [getLast_cons, getLast_filter' (b :: as) _ h'] exact ne_nil_of_mem <| mem_filter.2 ⟨getLast_mem _, h'⟩ · simp only [ha, cond_false] at h ⊢ - exact getLast_filter (b :: as) h h' + exact getLast_filter' (b :: as) h h' /-! ### getLast? -/ @@ -739,10 +739,10 @@ end IndexOf section deprecated @[simp] -theorem getElem?_length (l : List α) : l[l.length]? = none := getElem?_len_le le_rfl +theorem getElem?_length (l : List α) : l[l.length]? = none := getElem?_eq_none le_rfl @[deprecated getElem?_length (since := "2024-06-12")] -theorem get?_length (l : List α) : l.get? l.length = none := get?_len_le le_rfl +theorem get?_length (l : List α) : l.get? l.length = none := get?_eq_none le_rfl @[deprecated (since := "2024-05-03")] alias get?_injective := get?_inj @@ -831,49 +831,23 @@ theorem get_reverse (l : List α) (i : Nat) (h1 h2) : dsimp omega -set_option linter.deprecated false - theorem get_reverse' (l : List α) (n) (hn') : l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by - rw [eq_comm] - convert get_reverse l.reverse n (by simpa) n.2 using 1 simp theorem eq_cons_of_length_one {l : List α} (h : l.length = 1) : l = [l.get ⟨0, by omega⟩] := by refine ext_get (by convert h) fun n h₁ h₂ => ?_ - simp only [get_singleton] + simp congr omega end deprecated -theorem modifyTailIdx_modifyTailIdx {f g : List α → List α} (m : ℕ) : - ∀ (n) (l : List α), - (l.modifyTailIdx f n).modifyTailIdx g (m + n) = - l.modifyTailIdx (fun l => (f l).modifyTailIdx g m) n - | 0, _ => rfl - | _ + 1, [] => rfl - | n + 1, a :: l => congr_arg (List.cons a) (modifyTailIdx_modifyTailIdx m n l) - -@[deprecated (since := "2024-10-21")] -alias modifyNthTail_modifyNthTail := modifyTailIdx_modifyTailIdx - -theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : ℕ) (l : List α) - (h : n ≤ m) : - (l.modifyTailIdx f n).modifyTailIdx g m = - l.modifyTailIdx (fun l => (f l).modifyTailIdx g (m - n)) n := by - rcases Nat.exists_eq_add_of_le h with ⟨m, rfl⟩ - rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel] - @[deprecated (since := "2024-10-21")] alias modifyNthTail_modifyNthTail_le := modifyTailIdx_modifyTailIdx_le -theorem modifyTailIdx_modifyTailIdx_same {f g : List α → List α} (n : ℕ) (l : List α) : - (l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g ∘ f) n := by - rw [modifyTailIdx_modifyTailIdx_le n n l (le_refl n), Nat.sub_self]; rfl - @[deprecated (since := "2024-10-21")] -alias modifyNthTail_modifyNthTail_same := modifyTailIdx_modifyTailIdx_same +alias modifyNthTail_modifyNthTail_same := modifyTailIdx_modifyTailIdx_self @[deprecated (since := "2024-05-04")] alias removeNth_eq_nthTail := eraseIdx_eq_modifyTailIdx @[deprecated (since := "2024-10-21")] alias modifyNth_eq_set := modify_eq_set @@ -1043,8 +1017,8 @@ theorem zipWith_flip (f : α → β → γ) : ∀ as bs, zipWith (flip f) bs as (x.drop m).take n ++ x.drop (n + m) = x.drop m := by rw [Nat.add_comm, drop_take_append_drop] /-- `take_concat_get` in simp normal form -/ -@[simp] lemma take_concat_get' (l : List α) (i : ℕ) (h : i < l.length) : - l.take i ++ [l[i]] = l.take (i + 1) := by simpa using take_concat_get l i h +lemma take_concat_get' (l : List α) (i : ℕ) (h : i < l.length) : + l.take i ++ [l[i]] = l.take (i + 1) := by simp /-- `eq_nil_or_concat` in simp normal form -/ lemma eq_nil_or_concat' (l : List α) : l = [] ∨ ∃ L b, l = L ++ [b] := by diff --git a/Mathlib/Data/List/Count.lean b/Mathlib/Data/List/Count.lean index 13c127b563b2a..c9608f6a4c96f 100644 --- a/Mathlib/Data/List/Count.lean +++ b/Mathlib/Data/List/Count.lean @@ -13,9 +13,8 @@ This file proves basic properties of `List.countP` and `List.count`, which count elements of a list satisfying a predicate and equal to a given element respectively. -/ +assert_not_exists Monoid assert_not_exists Set.range -assert_not_exists GroupWithZero -assert_not_exists Ring open Nat @@ -23,9 +22,24 @@ variable {α : Type*} namespace List -/-! ### count -/ - -section Count +lemma countP_erase [DecidableEq α] (p : α → Bool) (l : List α) (a : α) : + countP p (l.erase a) = countP p l - if a ∈ l ∧ p a then 1 else 0 := by + rw [countP_eq_length_filter, countP_eq_length_filter, ← erase_filter, length_erase] + aesop + +lemma count_diff [DecidableEq α] (a : α) (l₁ : List α) : + ∀ l₂, count a (l₁.diff l₂) = count a l₁ - count a l₂ + | [] => rfl + | b :: l₂ => by + simp only [diff_cons, count_diff, count_erase, beq_iff_eq, Nat.sub_right_comm, count_cons, + Nat.sub_add_eq] + +lemma countP_diff [DecidableEq α] {l₁ l₂ : List α} (hl : l₂ <+~ l₁) (p : α → Bool) : + countP p (l₁.diff l₂) = countP p l₁ - countP p l₂ := by + refine (Nat.sub_eq_of_eq_add ?_).symm + rw [← countP_append] + exact ((subperm_append_diff_self_of_count_le <| subperm_ext_iff.1 hl).symm.trans + perm_append_comm).countP_eq _ @[simp] theorem count_map_of_injective {β} [DecidableEq α] [DecidableEq β] (l : List α) (f : α → β) @@ -34,6 +48,4 @@ theorem count_map_of_injective {β} [DecidableEq α] [DecidableEq β] (l : List unfold Function.comp simp only [hf.beq_eq] -end Count - end List diff --git a/Mathlib/Data/List/Cycle.lean b/Mathlib/Data/List/Cycle.lean index 167f0c1116671..34485c3ee467f 100644 --- a/Mathlib/Data/List/Cycle.lean +++ b/Mathlib/Data/List/Cycle.lean @@ -217,7 +217,7 @@ theorem prev_ne_cons_cons (y z : α) (h : x ∈ y :: z :: l) (hy : x ≠ y) (hz · rw [prev, dif_neg hy, if_neg hz] theorem next_mem (h : x ∈ l) : l.next x h ∈ l := - nextOr_mem (get_mem _ _ _) + nextOr_mem (get_mem _ _) theorem prev_mem (h : x ∈ l) : l.prev x h ∈ l := by cases' l with hd tl @@ -233,7 +233,7 @@ theorem prev_mem (h : x ∈ l) : l.prev x h ∈ l := by · exact mem_cons_of_mem _ (hl _ _) theorem next_get (l : List α) (h : Nodup l) (i : Fin l.length) : - next l (l.get i) (get_mem _ _ _) = + next l (l.get i) (get_mem _ _) = l.get ⟨(i + 1) % l.length, Nat.mod_lt _ (i.1.zero_le.trans_lt i.2)⟩ := match l, h, i with | [], _, i => by simpa using i.2 @@ -254,7 +254,7 @@ theorem next_get (l : List α) (h : Nodup l) (i : Fin l.length) : · subst hi' rw [next_getLast_cons] · simp [hi', get] - · rw [get_cons_succ]; exact get_mem _ _ _ + · rw [get_cons_succ]; exact get_mem _ _ · exact hx' · simp [getLast_eq_getElem] · exact hn.of_cons @@ -271,12 +271,12 @@ theorem next_get (l : List α) (h : Nodup l) (i : Fin l.length) : intro h have := nodup_iff_injective_get.1 hn h simp at this; simp [this] at hi' - · rw [get_cons_succ]; exact get_mem _ _ _ + · rw [get_cons_succ]; exact get_mem _ _ -- Unused variable linter incorrectly reports that `h` is unused here. set_option linter.unusedVariables false in theorem prev_get (l : List α) (h : Nodup l) (i : Fin l.length) : - prev l (l.get i) (get_mem _ _ _) = + prev l (l.get i) (get_mem _ _) = l.get ⟨(i + (l.length - 1)) % l.length, Nat.mod_lt _ i.pos⟩ := match l with | [] => by simpa using i.2 diff --git a/Mathlib/Data/List/Destutter.lean b/Mathlib/Data/List/Destutter.lean index df3a1ad3b5778..f021d2425e7a0 100644 --- a/Mathlib/Data/List/Destutter.lean +++ b/Mathlib/Data/List/Destutter.lean @@ -25,8 +25,11 @@ Note that we make no guarantees of being the longest sublist with this property; adjacent, chain, duplicates, remove, list, stutter, destutter -/ +open Function -variable {α : Type*} (l : List α) (R : α → α → Prop) [DecidableRel R] {a b : α} +variable {α β : Type*} (l l₁ l₂ : List α) (R : α → α → Prop) [DecidableRel R] {a b : α} + +variable {R₂ : β → β → Prop} [DecidableRel R₂] namespace List @@ -148,4 +151,116 @@ theorem destutter_eq_nil : ∀ {l : List α}, destutter R l = [] ↔ l = [] | [] => Iff.rfl | _ :: l => ⟨fun h => absurd h <| l.destutter'_ne_nil R, fun h => nomatch h⟩ +variable {R} + +/-- For a relation-preserving map, `destutter` commutes with `map`. -/ +theorem map_destutter {f : α → β} : ∀ {l : List α}, (∀ a ∈ l, ∀ b ∈ l, R a b ↔ R₂ (f a) (f b)) → + (l.destutter R).map f = (l.map f).destutter R₂ + | [], hl => by simp + | [a], hl => by simp + | a :: b :: l, hl => by + have := hl a (by simp) b (by simp) + simp_rw [map_cons, destutter_cons_cons, ← this] + by_cases hr : R a b <;> + simp [hr, ← destutter_cons', map_destutter fun c hc d hd ↦ hl _ (cons_subset_cons _ + (subset_cons_self _ _) hc) _ (cons_subset_cons _ (subset_cons_self _ _) hd), + map_destutter fun c hc d hd ↦ hl _ (subset_cons_self _ _ hc) _ (subset_cons_self _ _ hd)] + +/-- For a injective function `f`, `destutter' (·≠·)` commutes with `map f`. -/ +theorem map_destutter_ne {f : α → β} (h : Injective f) [DecidableEq α] [DecidableEq β] : + (l.destutter (·≠·)).map f = (l.map f).destutter (·≠·) := + map_destutter fun _ _ _ _ ↦ h.ne_iff.symm + +/-- `destutter'` on a relation like ≠ or <, whose negation is transitive, has length monotone +under a `¬R` changing of the first element. -/ +theorem length_destutter'_cotrans_ge [i : IsTrans α Rᶜ] : + ∀ {a} {l : List α}, ¬R b a → (l.destutter' R b).length ≤ (l.destutter' R a).length + | a, [], hba => by simp + | a, c :: l, hba => by + by_cases hbc : R b c + case pos => + have hac : ¬Rᶜ a c := (mt (_root_.trans hba)) (not_not.2 hbc) + simp_rw [destutter', if_pos (not_not.1 hac), if_pos hbc, length_cons, le_refl] + case neg => + simp only [destutter', if_neg hbc] + by_cases hac : R a c + case pos => + simp only [if_pos hac, length_cons] + exact Nat.le_succ_of_le (length_destutter'_cotrans_ge hbc) + case neg => + simp only [if_neg hac] + exact length_destutter'_cotrans_ge hba + +/-- `List.destutter'` on a relation like `≠`, whose negation is an equivalence, gives the same +length if the first elements are not related. -/ +theorem length_destutter'_congr [IsEquiv α Rᶜ] (hab : ¬R a b) : + (l.destutter' R a).length = (l.destutter' R b).length := + (length_destutter'_cotrans_ge hab).antisymm <| length_destutter'_cotrans_ge (symm hab : Rᶜ b a) + +/-- `List.destutter'` on a relation like ≠, whose negation is an equivalence, has length + monotonic under List.cons -/ +/- +TODO: Replace this lemma by the more general version: +theorem Sublist.length_destutter'_mono [IsEquiv α Rᶜ] (h : a :: l₁ <+ b :: l₂) : + (List.destutter' R a l₁).length ≤ (List.destutter' R b l₂).length +-/ +theorem le_length_destutter'_cons [IsEquiv α Rᶜ] : + ∀ {l : List α}, (l.destutter' R b).length ≤ ((b :: l).destutter' R a).length + | [] => by by_cases hab : (R a b) <;> simp_all [Nat.le_succ] + | c :: cs => by + by_cases hab : R a b + case pos => simp [destutter', if_pos hab, Nat.le_succ] + obtain hac | hac : R a c ∨ Rᶜ a c := em _ + · have hbc : ¬Rᶜ b c := mt (_root_.trans hab) (not_not.2 hac) + simp [destutter', if_pos hac, if_pos (not_not.1 hbc), if_neg hab] + · have hbc : ¬R b c := trans (symm hab) hac + simp only [destutter', if_neg hbc, if_neg hac, if_neg hab] + exact (length_destutter'_congr cs hab).ge + +/-- `List.destutter` on a relation like ≠, whose negation is an equivalence, has length +monotone under List.cons -/ +theorem length_destutter_le_length_destutter_cons [IsEquiv α Rᶜ] : + ∀ {l : List α}, (l.destutter R).length ≤ ((a :: l).destutter R).length + | [] => by simp [destutter] + | b :: l => le_length_destutter'_cons + +variable {l l₁ l₂} + +/-- `destutter ≠` has length monotone under `List.cons`. -/ +theorem length_destutter_ne_le_length_destutter_cons [DecidableEq α] : + (l.destutter (· ≠ ·)).length ≤ ((a :: l).destutter (· ≠ ·)).length := + length_destutter_le_length_destutter_cons + +/-- `destutter` of relations like `≠`, whose negation is an equivalence relation, +gives a list of maximal length over any chain. + +In other words, `l.destutter R` is an `R`-chain sublist of `l`, and is at least as long as any other +`R`-chain sublist. -/ +lemma Chain'.length_le_length_destutter [IsEquiv α Rᶜ] : + ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → l₁.Chain' R → l₁.length ≤ (l₂.destutter R).length + -- `l₁ := []`, `l₂ := []` + | [], [], _, _ => by simp + -- `l₁ := l₁`, `l₂ := a :: l₂` + | l₁, _, .cons (l₂ := l₂) a hl, hl₁ => + (hl₁.length_le_length_destutter hl).trans length_destutter_le_length_destutter_cons + -- `l₁ := [a]`, `l₂ := a :: l₂` + | _, _, .cons₂ (l₁ := []) (l₂ := l₁) a hl, hl₁ => by simp [Nat.one_le_iff_ne_zero] + -- `l₁ := a :: l₁`, `l₂ := a :: b :: l₂` + | _, _, .cons₂ a <| .cons (l₁ := l₁) (l₂ := l₂) b hl, hl₁ => by + by_cases hab : R a b + · simpa [destutter_cons_cons, hab] using hl₁.tail.length_le_length_destutter (hl.cons _) + · simpa [destutter_cons_cons, hab] using hl₁.length_le_length_destutter (hl.cons₂ _) + -- `l₁ := a :: b :: l₁`, `l₂ := a :: b :: l₂` + | _, _, .cons₂ a <| .cons₂ (l₁ := l₁) (l₂ := l₂) b hl, hl₁ => by + simpa [destutter_cons_cons, rel_of_chain_cons hl₁] + using hl₁.tail.length_le_length_destutter (hl.cons₂ _) + +/-- `destutter` of `≠` gives a list of maximal length over any chain. + +In other words, `l.destutter (· ≠ ·)` is a `≠`-chain sublist of `l`, and is at least as long as any +other `≠`-chain sublist. -/ +lemma Chain'.length_le_length_destutter_ne [DecidableEq α] (hl : l₁ <+ l₂) + (hl₁ : l₁.Chain' (· ≠ ·)) : l₁.length ≤ (l₂.destutter (· ≠ ·)).length := + hl₁.length_le_length_destutter hl + end List diff --git a/Mathlib/Data/List/DropRight.lean b/Mathlib/Data/List/DropRight.lean index f55afc95cdd9f..ad7f1c36acb62 100644 --- a/Mathlib/Data/List/DropRight.lean +++ b/Mathlib/Data/List/DropRight.lean @@ -138,18 +138,9 @@ theorem dropWhile_eq_self_iff : dropWhile p l = l ↔ ∀ hl : 0 < l.length, ¬p rw [get] at this simp_rw [this] -/- porting note: This proof is longer than it used to be because `simp` refuses to rewrite - the `l ≠ []` condition if `hl` is not `intro`'d yet -/ @[simp] theorem rdropWhile_eq_self_iff : rdropWhile p l = l ↔ ∀ hl : l ≠ [], ¬p (l.getLast hl) := by - simp only [rdropWhile, reverse_eq_iff, dropWhile_eq_self_iff, getLast_eq_getElem] - refine ⟨fun h hl => ?_, fun h hl => ?_⟩ - · rw [← length_pos, ← length_reverse] at hl - have := h hl - rwa [get_reverse'] at this - · rw [length_reverse, length_pos] at hl - have := h hl - rwa [get_reverse'] + simp [rdropWhile, reverse_eq_iff, getLast_eq_getElem, Nat.pos_iff_ne_zero] variable (p) (l) diff --git a/Mathlib/Data/List/FinRange.lean b/Mathlib/Data/List/FinRange.lean index 83ccab9a12979..8281f5ce92052 100644 --- a/Mathlib/Data/List/FinRange.lean +++ b/Mathlib/Data/List/FinRange.lean @@ -5,7 +5,6 @@ Authors: Mario Carneiro, Kenny Lau, Kim Morrison, Alex Keizer -/ import Mathlib.Data.List.OfFn import Batteries.Data.List.Perm -import Batteries.Data.List.FinRange import Mathlib.Data.List.Nodup /-! diff --git a/Mathlib/Data/List/GetD.lean b/Mathlib/Data/List/GetD.lean index 33af5b90cdb00..9e93d425fe171 100644 --- a/Mathlib/Data/List/GetD.lean +++ b/Mathlib/Data/List/GetD.lean @@ -49,6 +49,11 @@ theorem getD_eq_default {n : ℕ} (hn : l.length ≤ n) : l.getD n d = d := by · simp at hn · exact ih (Nat.le_of_succ_le_succ hn) +theorem getD_reverse {l : List α} (i) (h : i < length l) : + getD l.reverse i = getD l (l.length - 1 - i) := by + funext a + rwa [List.getD_eq_getElem?_getD, List.getElem?_reverse, ← List.getD_eq_getElem?_getD] + /-- An empty list can always be decidably checked for the presence of an element. Not an instance because it would clash with `DecidableEq α`. -/ def decidableGetDNilNe (a : α) : DecidablePred fun i : ℕ => getD ([] : List α) i a ≠ a := @@ -69,6 +74,11 @@ theorem getElem?_getD_replicate_default_eq (r n : ℕ) : (replicate r d)[n]?.get @[deprecated (since := "2024-06-12")] alias getD_replicate_default_eq := getElem?_getD_replicate_default_eq +theorem getD_replicate {y i n} (h : i < n) : + getD (replicate n x) i y = x := by + rw [getD_eq_getElem, getElem_replicate] + rwa [length_replicate] + theorem getD_append (l l' : List α) (d : α) (n : ℕ) (h : n < l.length) : (l ++ l').getD n d = l.getD n d := by rw [getD_eq_getElem _ _ (Nat.lt_of_lt_of_le h (length_append _ _ ▸ Nat.le_add_right _ _)), @@ -86,7 +96,7 @@ theorem getD_append_right (l l' : List α) (d : α) (n : ℕ) (h : l.length ≤ theorem getD_eq_getD_get? (n : ℕ) : l.getD n d = (l.get? n).getD d := by cases Nat.lt_or_ge n l.length with | inl h => rw [getD_eq_getElem _ _ h, get?_eq_get h, get_eq_getElem, Option.getD_some] - | inr h => rw [getD_eq_default _ _ h, get?_eq_none.mpr h, Option.getD_none] + | inr h => rw [getD_eq_default _ _ h, get?_eq_none_iff.mpr h, Option.getD_none] end getD diff --git a/Mathlib/Data/List/Indexes.lean b/Mathlib/Data/List/Indexes.lean index fdbe9168bfa47..dfa2e8e7d9973 100644 --- a/Mathlib/Data/List/Indexes.lean +++ b/Mathlib/Data/List/Indexes.lean @@ -3,7 +3,6 @@ Copyright (c) 2020 Jannis Limperg. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Jannis Limperg -/ -import Mathlib.Data.List.OfFn import Mathlib.Data.List.Basic /-! @@ -36,16 +35,11 @@ theorem list_reverse_induction (p : List α → Prop) (base : p []) · apply pq; simp only [reverse_nil, base] · apply pq; simp only [reverse_cons]; apply ind; apply qp; rw [reverse_reverse]; exact ih -@[deprecated (since := "2024-10-15")] alias mapIdxGo_append := mapIdx_go_append @[deprecated (since := "2024-10-15")] alias mapIdxGo_length := mapIdx_go_length -theorem mapIdx_append_one : ∀ (f : ℕ → α → β) (l : List α) (e : α), - mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := by - intros f l e - unfold mapIdx - rw [mapIdx_go_append] - simp only [mapIdx.go, Array.size_toArray, mapIdx_go_length, length_nil, Nat.add_zero, - Array.push_toList, Array.toList_toArray] +theorem mapIdx_append_one : ∀ {f : ℕ → α → β} {l : List α} {e : α}, + mapIdx f (l ++ [e]) = mapIdx f l ++ [f l.length e] := + mapIdx_concat @[local simp] theorem map_enumFrom_eq_zipWith : ∀ (l : List α) (n : ℕ) (f : ℕ → α → β), @@ -292,9 +286,8 @@ theorem mapIdxMAux'_eq_mapIdxMGo {α} (f : ℕ → α → m PUnit) (as : List α · simp only [mapIdxMAux', seqRight_eq, map_eq_pure_bind, seq_eq_bind, bind_pure_unit, LawfulMonad.bind_assoc, pure_bind, mapIdxM.go, seq_pure] generalize (f (Array.size arr) head) = head - let arr_1 := arr.push ⟨⟩ - have : arr_1.size = arr.size + 1 := Array.size_push arr ⟨⟩ - rw [← this, ih arr_1] + have : (arr.push ⟨⟩).size = arr.size + 1 := Array.size_push arr ⟨⟩ + rw [← this, ih] simp only [seqRight_eq, map_eq_pure_bind, seq_pure, LawfulMonad.bind_assoc, pure_bind] theorem mapIdxM'_eq_mapIdxM {α} (f : ℕ → α → m PUnit) (as : List α) : diff --git a/Mathlib/Data/List/InsertIdx.lean b/Mathlib/Data/List/InsertIdx.lean index 7c1c61e68cdc2..431b9703de66b 100644 --- a/Mathlib/Data/List/InsertIdx.lean +++ b/Mathlib/Data/List/InsertIdx.lean @@ -27,143 +27,27 @@ section InsertIdx variable {a : α} -@[simp] -theorem insertIdx_zero (s : List α) (x : α) : insertIdx 0 x s = x :: s := - rfl - -@[simp] -theorem insertIdx_succ_nil (n : ℕ) (a : α) : insertIdx (n + 1) a [] = [] := - rfl - -@[simp] -theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : ℕ) : - insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s := - rfl - -theorem length_insertIdx : ∀ n as, n ≤ length as → length (insertIdx n a as) = length as + 1 - | 0, _, _ => rfl - | _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim - | n + 1, _ :: as, h => congr_arg Nat.succ <| length_insertIdx n as (Nat.le_of_succ_le_succ h) - -theorem eraseIdx_insertIdx (n : ℕ) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by - rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_same] - exact modifyTailIdx_id _ _ - -theorem insertIdx_eraseIdx_of_ge : - ∀ n m as, - n < length as → n ≤ m → insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n - | 0, 0, [], has, _ => (lt_irrefl _ has).elim - | 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx] - | 0, _ + 1, _ :: _, _, _ => rfl - | n + 1, m + 1, a :: as, has, hmn => - congr_arg (cons a) <| - insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn) - -theorem insertIdx_eraseIdx_of_le : - ∀ n m as, - n < length as → m ≤ n → insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1) - | _, 0, _ :: _, _, _ => rfl - | n + 1, m + 1, a :: as, has, hmn => - congr_arg (cons a) <| - insertIdx_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn) - -theorem insertIdx_comm (a b : α) : - ∀ (i j : ℕ) (l : List α) (_ : i ≤ j) (_ : j ≤ length l), - (l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a - | 0, j, l => by simp [insertIdx] - | _ + 1, 0, _ => fun h => (Nat.not_lt_zero _ h).elim - | i + 1, j + 1, [] => by simp - | i + 1, j + 1, c :: l => fun h₀ h₁ => by - simp only [insertIdx_succ_cons, cons.injEq, true_and] - exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁) - -theorem mem_insertIdx {a b : α} : - ∀ {n : ℕ} {l : List α} (_ : n ≤ l.length), a ∈ l.insertIdx n b ↔ a = b ∨ a ∈ l - | 0, as, _ => by simp - | _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim - | n + 1, a' :: as, h => by - rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h), - ← or_assoc, @or_comm (a = a'), or_assoc, mem_cons] - -theorem insertIdx_of_length_lt (l : List α) (x : α) (n : ℕ) (h : l.length < n) : - insertIdx n x l = l := by - induction' l with hd tl IH generalizing n - · cases n - · simp at h - · simp - · cases n - · simp at h - · simp only [Nat.succ_lt_succ_iff, length] at h - simpa using IH _ h - -@[simp] -theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l = l ++ [x] := by - induction' l with hd tl IH - · simp - · simpa using IH - -theorem length_le_length_insertIdx (l : List α) (x : α) (n : ℕ) : - l.length ≤ (insertIdx n x l).length := by - rcases le_or_lt n l.length with hn | hn - · rw [length_insertIdx _ _ hn] - exact (Nat.lt_succ_self _).le - · rw [insertIdx_of_length_lt _ _ _ hn] - -theorem length_insertIdx_le_succ (l : List α) (x : α) (n : ℕ) : - (insertIdx n x l).length ≤ l.length + 1 := by - rcases le_or_lt n l.length with hn | hn - · rw [length_insertIdx _ _ hn] - · rw [insertIdx_of_length_lt _ _ _ hn] - exact (Nat.lt_succ_self _).le - -theorem getElem_insertIdx_of_lt (l : List α) (x : α) (n k : ℕ) (hn : k < n) (hk : k < l.length) - (hk' : k < (insertIdx n x l).length := hk.trans_le (length_le_length_insertIdx _ _ _)) : - (insertIdx n x l)[k] = l[k] := by - induction' n with n IH generalizing k l - · simp at hn - · cases' l with hd tl - · simp - · cases k - · simp [get] - · rw [Nat.succ_lt_succ_iff] at hn - simpa using IH _ _ hn _ - theorem get_insertIdx_of_lt (l : List α) (x : α) (n k : ℕ) (hn : k < n) (hk : k < l.length) (hk' : k < (insertIdx n x l).length := hk.trans_le (length_le_length_insertIdx _ _ _)) : (insertIdx n x l).get ⟨k, hk'⟩ = l.get ⟨k, hk⟩ := by simp_all [getElem_insertIdx_of_lt] -@[simp] -theorem getElem_insertIdx_self (l : List α) (x : α) (n : ℕ) (hn : n ≤ l.length) - (hn' : n < (insertIdx n x l).length := (by rwa [length_insertIdx _ _ hn, Nat.lt_succ_iff])) : - (insertIdx n x l)[n] = x := by - induction' l with hd tl IH generalizing n - · simp only [length] at hn - cases hn - simp only [insertIdx_zero, getElem_singleton] - · cases n - · simp - · simp only [Nat.succ_le_succ_iff, length] at hn - simpa using IH _ hn - theorem get_insertIdx_self (l : List α) (x : α) (n : ℕ) (hn : n ≤ l.length) - (hn' : n < (insertIdx n x l).length := (by rwa [length_insertIdx _ _ hn, Nat.lt_succ_iff])) : + (hn' : n < (insertIdx n x l).length := + (by rwa [length_insertIdx_of_le_length hn, Nat.lt_succ_iff])) : (insertIdx n x l).get ⟨n, hn'⟩ = x := by simp [hn, hn'] theorem getElem_insertIdx_add_succ (l : List α) (x : α) (n k : ℕ) (hk' : n + k < l.length) (hk : n + k + 1 < (insertIdx n x l).length := (by - rwa [length_insertIdx _ _ (by omega), Nat.succ_lt_succ_iff])) : + rwa [length_insertIdx_of_le_length (by omega), Nat.succ_lt_succ_iff])) : (insertIdx n x l)[n + k + 1] = l[n + k] := by - induction' l with hd tl IH generalizing n k - · simp at hk' - · cases n - · simp - · simpa [Nat.add_right_comm] using IH _ _ _ + rw [getElem_insertIdx_of_ge (by omega)] + simp only [Nat.add_one_sub_one] theorem get_insertIdx_add_succ (l : List α) (x : α) (n k : ℕ) (hk' : n + k < l.length) (hk : n + k + 1 < (insertIdx n x l).length := (by - rwa [length_insertIdx _ _ (by omega), Nat.succ_lt_succ_iff])) : + rwa [length_insertIdx_of_le_length (by omega), Nat.succ_lt_succ_iff])) : (insertIdx n x l).get ⟨n + k + 1, hk⟩ = get l ⟨n + k, hk'⟩ := by simp [getElem_insertIdx_add_succ, hk, hk'] diff --git a/Mathlib/Data/List/Intervals.lean b/Mathlib/Data/List/Intervals.lean index 9c89237d400af..bfc2d2a858d87 100644 --- a/Mathlib/Data/List/Intervals.lean +++ b/Mathlib/Data/List/Intervals.lean @@ -29,8 +29,9 @@ namespace List /-- `Ico n m` is the list of natural numbers `n ≤ x < m`. (Ico stands for "interval, closed-open".) -See also `Data/Set/Intervals.lean` for `Set.Ico`, modelling intervals in general preorders, and -`Multiset.Ico` and `Finset.Ico` for `n ≤ x < m` as a multiset or as a finset. +See also `Order/Interval/Basic.lean` for modelling intervals in general preorders, as well as +sibling definitions alongside it such as `Set.Ico`, `Multiset.Ico` and `Finset.Ico` +for sets, multisets and finite sets respectively. -/ def Ico (n m : ℕ) : List ℕ := range' n (m - n) @@ -130,7 +131,7 @@ theorem not_mem_top {n m : ℕ} : m ∉ Ico n m := by simp theorem filter_lt_of_top_le {n m l : ℕ} (hml : m ≤ l) : ((Ico n m).filter fun x => x < l) = Ico n m := filter_eq_self.2 fun k hk => by - simp only [(lt_of_lt_of_le (mem.1 hk).2 hml), decide_True] + simp only [(lt_of_lt_of_le (mem.1 hk).2 hml), decide_true] theorem filter_lt_of_le_bot {n m l : ℕ} (hln : l ≤ n) : ((Ico n m).filter fun x => x < l) = [] := filter_eq_nil_iff.2 fun k hk => by diff --git a/Mathlib/Data/List/Lemmas.lean b/Mathlib/Data/List/Lemmas.lean index 50f55ed3f3832..a6c98a38f2db9 100644 --- a/Mathlib/Data/List/Lemmas.lean +++ b/Mathlib/Data/List/Lemmas.lean @@ -17,6 +17,18 @@ variable {α β γ : Type*} namespace List +@[simp] +theorem length_flatMap (l : List α) (f : α → List β) : + length (List.flatMap l f) = sum (map (length ∘ f) l) := by + rw [List.flatMap, length_flatten, map_map] + +lemma countP_flatMap (p : β → Bool) (l : List α) (f : α → List β) : + countP p (l.flatMap f) = sum (map (countP p ∘ f) l) := by + rw [List.flatMap, countP_flatten, map_map] + +lemma count_flatMap [BEq β] (l : List α) (f : α → List β) (x : β) : + count x (l.flatMap f) = sum (map (count x ∘ f) l) := countP_flatMap _ _ _ + @[deprecated (since := "2024-08-20")] alias getElem_reverse' := getElem_reverse theorem tail_reverse_eq_reverse_dropLast (l : List α) : diff --git a/Mathlib/Data/List/MinMax.lean b/Mathlib/Data/List/MinMax.lean index 2a7dbf99b60f2..5ed4618178ea5 100644 --- a/Mathlib/Data/List/MinMax.lean +++ b/Mathlib/Data/List/MinMax.lean @@ -89,7 +89,7 @@ end ArgAux section Preorder -variable [Preorder β] [@DecidableRel β (· < ·)] {f : α → β} {l : List α} {a m : α} +variable [Preorder β] [DecidableRel (α := β) (· < ·)] {f : α → β} {l : List α} {a m : α} /-- `argmax f l` returns `some a`, where `f a` is maximal among the elements of `l`, in the sense that there is no `b ∈ l` with `f a < f b`. If `a`, `b` are such that `f a = f b`, it returns @@ -243,7 +243,7 @@ section MaximumMinimum section Preorder -variable [Preorder α] [@DecidableRel α (· < ·)] {l : List α} {a m : α} +variable [Preorder α] [DecidableRel (α := α) (· < ·)] {l : List α} {a m : α} /-- `maximum l` returns a `WithBot α`, the largest element of `l` for nonempty lists, and `⊥` for `[]` -/ diff --git a/Mathlib/Data/List/NodupEquivFin.lean b/Mathlib/Data/List/NodupEquivFin.lean index 65a48a57e4574..b53d6dbaf8777 100644 --- a/Mathlib/Data/List/NodupEquivFin.lean +++ b/Mathlib/Data/List/NodupEquivFin.lean @@ -49,7 +49,7 @@ variable [DecidableEq α] the set of elements of `l`. -/ @[simps] def getEquiv (l : List α) (H : Nodup l) : Fin (length l) ≃ { x // x ∈ l } where - toFun i := ⟨get l i, get_mem l i i.2⟩ + toFun i := ⟨get l i, get_mem _ _⟩ invFun x := ⟨indexOf (↑x) l, indexOf_lt_length.2 x.2⟩ left_inv i := by simp only [List.get_indexOf, eq_self_iff_true, Fin.eta, Subtype.coe_mk, H] right_inv x := by simp @@ -108,7 +108,7 @@ theorem sublist_of_orderEmbedding_get?_eq {l l' : List α} (f : ℕ ↪o ℕ) induction' l with hd tl IH generalizing l' f · simp have : some hd = _ := hf 0 - rw [eq_comm, List.get?_eq_some] at this + rw [eq_comm, List.get?_eq_some_iff] at this obtain ⟨w, h⟩ := this let f' : ℕ ↪o ℕ := OrderEmbedding.ofMapLEIff (fun i => f (i + 1) - (f 0 + 1)) fun a b => by @@ -168,7 +168,7 @@ theorem sublist_iff_exists_fin_orderEmbedding_get_eq {l l' : List α} : 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 + rw [get?_eq_get hi, eq_comm, get?_eq_some_iff] at hf obtain ⟨h, -⟩ := hf exact h refine ⟨OrderEmbedding.ofMapLEIff (fun ix => ⟨f ix, h ix.is_lt⟩) ?_, ?_⟩ @@ -193,7 +193,7 @@ theorem sublist_iff_exists_fin_orderEmbedding_get_eq {l l' : List α} : simp only [OrderEmbedding.coe_ofStrictMono] split_ifs with hi · rw [get?_eq_get hi, get?_eq_get, ← hf] - · rw [get?_eq_none.mpr, get?_eq_none.mpr] + · rw [get?_eq_none_iff.mpr, get?_eq_none_iff.mpr] · simp · simpa using hi diff --git a/Mathlib/Data/List/OfFn.lean b/Mathlib/Data/List/OfFn.lean index 0e55bda4eaa55..ac14755a5fd6d 100644 --- a/Mathlib/Data/List/OfFn.lean +++ b/Mathlib/Data/List/OfFn.lean @@ -3,7 +3,6 @@ Copyright (c) 2018 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Batteries.Data.List.OfFn import Mathlib.Data.Fin.Tuple.Basic /-! @@ -36,7 +35,7 @@ theorem get_ofFn {n} (f : Fin n → α) (i) : get (ofFn f) i = f (Fin.cast (by s /-- The `n`th element of a list -/ theorem get?_ofFn {n} (f : Fin n → α) (i) : get? (ofFn f) i = ofFnNthVal f i := by - simp + simp [ofFnNthVal] @[simp] theorem map_ofFn {β : Type*} {n : ℕ} (f : Fin n → α) (g : α → β) : @@ -59,18 +58,6 @@ theorem ofFn_congr {m n : ℕ} (h : m = n) (f : Fin m → α) : subst h simp_rw [Fin.cast_refl, id] -/-- `ofFn` on an empty domain is the empty list. -/ -@[simp] -theorem ofFn_zero (f : Fin 0 → α) : ofFn f = [] := - ext_get (by simp) (fun i hi₁ hi₂ => by contradiction) - -@[simp] -theorem ofFn_succ {n} (f : Fin (succ n) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ := - ext_get (by simp) (fun i hi₁ hi₂ => by - cases i - · simp - · simp) - theorem ofFn_succ' {n} (f : Fin (succ n) → α) : ofFn f = (ofFn fun i => f (Fin.castSucc i)).concat (f (Fin.last _)) := by induction' n with n IH @@ -79,10 +66,6 @@ theorem ofFn_succ' {n} (f : Fin (succ n) → α) : · rw [ofFn_succ, IH, ofFn_succ, concat_cons, Fin.castSucc_zero] congr -@[simp] -theorem ofFn_eq_nil_iff {n : ℕ} {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by - cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq] - /-- Note this matches the convention of `List.ofFn_succ'`, putting the `Fin m` elements first. -/ theorem ofFn_add {m n} (f : Fin (m + n) → α) : List.ofFn f = @@ -172,15 +155,6 @@ theorem pairwise_ofFn {R : α → α → Prop} {n} {f : Fin n → α} : (Fin.rightInverse_cast (length_ofFn f)).surjective.forall, Fin.forall_iff, Fin.cast_mk, Fin.mk_lt_mk, forall_comm (α := (_ : Prop)) (β := ℕ)] -lemma head_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) : - (ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by - rw [← getElem_zero (length_ofFn _ ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)), - List.getElem_ofFn] - -lemma getLast_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) : - (ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by - simp [getLast_eq_getElem] - lemma getLast_ofFn_succ {n : ℕ} (f : Fin n.succ → α) : (ofFn f).getLast (mt ofFn_eq_nil_iff.1 (Nat.succ_ne_zero _)) = f (Fin.last _) := getLast_ofFn f _ @@ -200,31 +174,6 @@ lemma ofFn_cons {n} (a : α) (f : Fin n → α) : ofFn (Fin.cons a f) = a :: ofF rw [ofFn_succ] rfl --- Temporary local copy of result from Lean commit 1e98fd7f2d965ab035dbf1099fb4a4ffde16b151. -theorem find?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {b : α} : - xs.find? p = some b ↔ p b ∧ ∃ i h, xs[i] = b ∧ ∀ j : Nat, (hj : j < i) → !p xs[j] := by - rw [find?_eq_some] - simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff] - intro w - constructor - · rintro ⟨as, ⟨bs, rfl⟩, h⟩ - refine ⟨as.length, ⟨?_, ?_, ?_⟩⟩ - · simp only [length_append, length_cons] - refine Nat.lt_add_of_pos_right (zero_lt_succ bs.length) - · rw [getElem_append_right (Nat.le_refl as.length)] - simp - · intro j h' - rw [getElem_append_left h'] - exact h _ (getElem_mem h') - · rintro ⟨i, h, rfl, h'⟩ - refine ⟨xs.take i, ⟨xs.drop (i+1), ?_⟩, ?_⟩ - · rw [getElem_cons_drop, take_append_drop] - · intro a m - rw [mem_take_iff_getElem] at m - obtain ⟨j, h, rfl⟩ := m - apply h' - omega - lemma find?_ofFn_eq_some {n} {f : Fin n → α} {p : α → Bool} {b : α} : (ofFn f).find? p = some b ↔ p b = true ∧ ∃ i, f i = b ∧ ∀ j < i, ¬(p (f j) = true) := by rw [find?_eq_some_iff_getElem] diff --git a/Mathlib/Data/List/Perm/Subperm.lean b/Mathlib/Data/List/Perm/Subperm.lean index bc574cf55a74d..3266017ace4f2 100644 --- a/Mathlib/Data/List/Perm/Subperm.lean +++ b/Mathlib/Data/List/Perm/Subperm.lean @@ -30,6 +30,11 @@ attribute [trans] Subperm.trans end Subperm +/-- See also `List.subperm_ext_iff`. -/ +lemma subperm_iff_count [DecidableEq α] : l₁ <+~ l₂ ↔ ∀ a, count a l₁ ≤ count a l₂ := + subperm_ext_iff.trans <| forall_congr' fun a ↦ by + by_cases ha : a ∈ l₁ <;> simp [ha, count_eq_zero_of_not_mem] + lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩ rintro ⟨l, h₁, h₂⟩ diff --git a/Mathlib/Data/List/Permutation.lean b/Mathlib/Data/List/Permutation.lean index 3e0073e3e2049..49f6dd007cd72 100644 --- a/Mathlib/Data/List/Permutation.lean +++ b/Mathlib/Data/List/Permutation.lean @@ -3,7 +3,7 @@ Copyright (c) 2014 Parikshit Khanna. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro -/ -import Mathlib.Data.List.Flatten +import Mathlib.Data.List.Lemmas import Mathlib.Data.Nat.Factorial.Basic import Mathlib.Data.List.Count import Mathlib.Data.List.Duplicate @@ -181,20 +181,18 @@ theorem mem_foldr_permutationsAux2 {t : α} {ts : List α} {r L : List (List α) simp only [mem_permutationsAux2', ← this, or_comm, and_left_comm, mem_append, mem_flatMap, append_assoc, cons_append, exists_prop] -set_option linter.deprecated false in theorem length_foldr_permutationsAux2 (t : α) (ts : List α) (r L : List (List α)) : length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = - Nat.sum (map length L) + length r := by - simp [foldr_permutationsAux2, Function.comp_def, length_permutationsAux2, length_flatMap'] + (map length L).sum + length r := by + simp [foldr_permutationsAux2, Function.comp_def, length_permutationsAux2, length_flatMap] -set_option linter.deprecated false in theorem length_foldr_permutationsAux2' (t : α) (ts : List α) (r L : List (List α)) (n) (H : ∀ l ∈ L, length l = n) : length (foldr (fun y r => (permutationsAux2 t ts r y id).2) r L) = n * length L + length r := by - rw [length_foldr_permutationsAux2, (_ : Nat.sum (map length L) = n * length L)] + rw [length_foldr_permutationsAux2, (_ : (map length L).sum = n * length L)] induction' L with l L ih · simp - have sum_map : Nat.sum (map length L) = n * length L := ih fun l m => H l (mem_cons_of_mem _ m) + have sum_map : (map length L).sum = n * length L := ih fun l m => H l (mem_cons_of_mem _ m) have length_l : length l = n := H _ (mem_cons_self _ _) simp [sum_map, length_l, Nat.mul_add, Nat.add_comm, mul_succ] @@ -410,7 +408,7 @@ theorem count_permutations'Aux_self [DecidableEq α] (l : List α) (x : α) : simpa [takeWhile, Nat.succ_inj', DecEq_eq] using IH _ · rw [takeWhile] simp only [mem_map, cons.injEq, Ne.symm hx, false_and, and_false, exists_false, - not_false_iff, count_eq_zero_of_not_mem, Nat.zero_add, hx, decide_False, length_nil] + not_false_iff, count_eq_zero_of_not_mem, Nat.zero_add, hx, decide_false, length_nil] @[simp] theorem length_permutations'Aux (s : List α) (x : α) : @@ -454,7 +452,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations' rw [← @Fin.mk.inj_iff _ _ _ kl k1l]; apply h rw [get_permutations'Aux, get_permutations'Aux] have hl : length (insertIdx k x s) = length (insertIdx (k + 1) x s) := by - rw [length_insertIdx _ _ hk.le, length_insertIdx _ _ (Nat.succ_le_of_lt hk)] + rw [length_insertIdx_of_le_length hk.le, length_insertIdx_of_le_length (Nat.succ_le_of_lt hk)] refine ext_get hl fun n hn hn' => ?_ rcases lt_trichotomy n k with (H | rfl | H) · rw [get_insertIdx_of_lt _ _ _ _ H (H.trans hk), @@ -465,7 +463,7 @@ theorem nodup_permutations'Aux_iff {s : List α} {x : α} : Nodup (permutations' convert hk' using 1 exact get_insertIdx_add_succ _ _ _ 0 _ · obtain ⟨m, rfl⟩ := Nat.exists_eq_add_of_lt H' - rw [length_insertIdx _ _ hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn + rw [length_insertIdx_of_le_length hk.le, Nat.succ_lt_succ_iff, Nat.succ_add] at hn rw [get_insertIdx_add_succ] · convert get_insertIdx_add_succ s x k m.succ (by simpa using hn) using 2 · simp [Nat.add_assoc, Nat.add_left_comm] @@ -492,21 +490,21 @@ theorem nodup_permutations (s : List α) (hs : Nodup s) : Nodup s.permutations : have hl : as.length = bs.length := (ha.trans hb.symm).length_eq simp only [Nat.lt_succ_iff, length_permutations'Aux] at hn hm rw [get_permutations'Aux] at hn' hm' - have hx : - (insertIdx n x as)[m]'(by rwa [length_insertIdx _ _ hn, Nat.lt_succ_iff, hl]) = x := by + have hx : (insertIdx n x as)[m]'(by + rwa [length_insertIdx_of_le_length hn, Nat.lt_succ_iff, hl]) = x := by simp [hn', ← hm', hm] - have hx' : - (insertIdx m x bs)[n]'(by rwa [length_insertIdx _ _ hm, Nat.lt_succ_iff, ← hl]) = x := by + have hx' : (insertIdx m x bs)[n]'(by + rwa [length_insertIdx_of_le_length hm, Nat.lt_succ_iff, ← hl]) = x := by simp [hm', ← hn', hn] rcases lt_trichotomy n m with (ht | ht | ht) · suffices x ∈ bs by exact h x (hb.subset this) rfl - rw [← hx', getElem_insertIdx_of_lt _ _ _ _ ht (ht.trans_le hm)] + rw [← hx', getElem_insertIdx_of_lt ht] exact getElem_mem _ · simp only [ht] at hm' hn' rw [← hm'] at hn' exact H (insertIdx_injective _ _ hn') · suffices x ∈ as by exact h x (ha.subset this) rfl - rw [← hx, getElem_insertIdx_of_lt _ _ _ _ ht (ht.trans_le hn)] + rw [← hx, getElem_insertIdx_of_lt ht] exact getElem_mem _ lemma permutations_take_two (x y : α) (s : List α) : diff --git a/Mathlib/Data/List/Sublists.lean b/Mathlib/Data/List/Sublists.lean index 9a2c8391406a8..aca81a62467f5 100644 --- a/Mathlib/Data/List/Sublists.lean +++ b/Mathlib/Data/List/Sublists.lean @@ -45,7 +45,7 @@ theorem sublists'Aux_eq_array_foldl (a : α) : ∀ (r₁ r₂ : List (List α)), sublists'Aux a r₁ r₂ = ((r₁.toArray).foldl (init := r₂.toArray) (fun r l => r.push (a :: l))).toList := by intro r₁ r₂ - rw [sublists'Aux, Array.foldl_eq_foldl_toList] + rw [sublists'Aux, Array.foldl_toList] have := List.foldl_hom Array.toList (fun r l => r.push (a :: l)) (fun r l => r ++ [a :: l]) r₁ r₂.toArray (by simp) simpa using this @@ -107,7 +107,7 @@ theorem sublistsAux_eq_array_foldl : (r.toArray.foldl (init := #[]) fun r l => (r.push l).push (a :: l)).toList := by funext a r - simp only [sublistsAux, Array.foldl_eq_foldl_toList, Array.mkEmpty] + simp only [sublistsAux, Array.foldl_toList, Array.mkEmpty] have := foldl_hom Array.toList (fun r l => (r.push l).push (a :: l)) (fun (r : List (List α)) l => r ++ [l, a :: l]) r #[] (by simp) @@ -128,7 +128,7 @@ theorem sublistsAux_eq_flatMap : ext α l : 2 trans l.foldr sublistsAux [[]] · rw [sublistsAux_eq_flatMap, sublists] - · simp only [sublistsFast, sublistsAux_eq_array_foldl, Array.foldr_eq_foldr_toList] + · simp only [sublistsFast, sublistsAux_eq_array_foldl, Array.foldr_toList] rw [← foldr_hom Array.toList] · intros _ _; congr diff --git a/Mathlib/Data/List/Sym.lean b/Mathlib/Data/List/Sym.lean index 1d6228b9258e3..b3981a8ba0333 100644 --- a/Mathlib/Data/List/Sym.lean +++ b/Mathlib/Data/List/Sym.lean @@ -170,7 +170,7 @@ theorem dedup_sym2 [DecidableEq α] (xs : List α) : xs.sym2.dedup = xs.dedup.sy obtain hm | hm := Decidable.em (x ∈ xs) · rw [dedup_cons_of_mem hm, ← ih, dedup_cons_of_mem, List.Subset.dedup_append_right (map_mk_sublist_sym2 _ _ hm).subset] - refine mem_append_of_mem_left _ ?_ + refine mem_append_left _ ?_ rw [mem_map] exact ⟨_, hm, Sym2.eq_swap⟩ · rw [dedup_cons_of_not_mem hm, List.sym2, map_cons, ← ih, dedup_cons_of_not_mem, cons_append, diff --git a/Mathlib/Data/List/TFAE.lean b/Mathlib/Data/List/TFAE.lean index 24e43d9612f03..55f77a0f094f9 100644 --- a/Mathlib/Data/List/TFAE.lean +++ b/Mathlib/Data/List/TFAE.lean @@ -62,7 +62,7 @@ theorem tfae_of_cycle {a b} {l : List Prop} (h_chain : List.Chain (· → ·) a theorem TFAE.out {l} (h : TFAE l) (n₁ n₂) {a b} (h₁ : List.get? l n₁ = some a := by rfl) (h₂ : List.get? l n₂ = some b := by rfl) : a ↔ b := - h _ (List.get?_mem h₁) _ (List.get?_mem h₂) + h _ (List.mem_of_get? h₁) _ (List.mem_of_get? h₂) /-- If `P₁ x ↔ ... ↔ Pₙ x` for all `x`, then `(∀ x, P₁ x) ↔ ... ↔ (∀ x, Pₙ x)`. Note: in concrete cases, Lean has trouble finding the list `[P₁, ..., Pₙ]` from the list diff --git a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean index 67906c2b869f0..c583ebb1d3b5e 100644 --- a/Mathlib/Data/Matrix/ColumnRowPartitioned.lean +++ b/Mathlib/Data/Matrix/ColumnRowPartitioned.lean @@ -4,15 +4,14 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mohanad Ahmed -/ -import Mathlib.Data.Matrix.Basic import Mathlib.Data.Matrix.Block -import Mathlib.LinearAlgebra.Matrix.NonsingularInverse +import Mathlib.LinearAlgebra.Matrix.SemiringInverse /-! # Block Matrices from Rows and Columns This file provides the basic definitions of matrices composed from columns and rows. The concatenation of two matrices with the same row indices can be expressed as -`A = fromColumns A₁ A₂` the concatenation of two matrices with the same column indices +`A = fromCols A₁ A₂` the concatenation of two matrices with the same column indices can be expressed as `B = fromRows B₁ B₂`. We then provide a few lemmas that deal with the products of these with each other and @@ -34,14 +33,14 @@ def fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : Matrix (m₁ /-- Concatenate together two matrices B₁[m × n₁] and B₂[m × n₂] with the same rows (M) to get a bigger matrix indexed by [m × (n₁ ⊕ n₂)] -/ -def fromColumns (B₁ : Matrix m n₁ R) (B₂ : Matrix m n₂ R) : Matrix m (n₁ ⊕ n₂) R := +def fromCols (B₁ : Matrix m n₁ R) (B₂ : Matrix m n₂ R) : Matrix m (n₁ ⊕ n₂) R := of fun i => Sum.elim (B₁ i) (B₂ i) /-- Given a column partitioned matrix extract the first column -/ -def toColumns₁ (A : Matrix m (n₁ ⊕ n₂) R) : Matrix m n₁ R := of fun i j => (A i (Sum.inl j)) +def toCols₁ (A : Matrix m (n₁ ⊕ n₂) R) : Matrix m n₁ R := of fun i j => (A i (Sum.inl j)) /-- Given a column partitioned matrix extract the second column -/ -def toColumns₂ (A : Matrix m (n₁ ⊕ n₂) R) : Matrix m n₂ R := of fun i j => (A i (Sum.inr j)) +def toCols₂ (A : Matrix m (n₁ ⊕ n₂) R) : Matrix m n₂ R := of fun i j => (A i (Sum.inr j)) /-- Given a row partitioned matrix extract the first row -/ def toRows₁ (A : Matrix (m₁ ⊕ m₂) n R) : Matrix m₁ n R := of fun i j => (A (Sum.inl i) j) @@ -49,6 +48,10 @@ def toRows₁ (A : Matrix (m₁ ⊕ m₂) n R) : Matrix m₁ n R := of fun i j = /-- Given a row partitioned matrix extract the second row -/ def toRows₂ (A : Matrix (m₁ ⊕ m₂) n R) : Matrix m₂ n R := of fun i j => (A (Sum.inr i) j) +@[deprecated (since := "2024-12-11")] alias fromColumns := fromCols +@[deprecated (since := "2024-12-11")] alias toColumns₁ := toCols₁ +@[deprecated (since := "2024-12-11")] alias toColumns₂ := toCols₂ + @[simp] lemma fromRows_apply_inl (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (i : m₁) (j : n) : (fromRows A₁ A₂) (Sum.inl i) j = A₁ i j := rfl @@ -58,12 +61,16 @@ lemma fromRows_apply_inr (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (i : (fromRows A₁ A₂) (Sum.inr i) j = A₂ i j := rfl @[simp] -lemma fromColumns_apply_inl (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (i : m) (j : n₁) : - (fromColumns A₁ A₂) i (Sum.inl j) = A₁ i j := rfl +lemma fromCols_apply_inl (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (i : m) (j : n₁) : + (fromCols A₁ A₂) i (Sum.inl j) = A₁ i j := rfl + +@[deprecated (since := "2024-12-11")] alias fromColumns_apply_inl := fromCols_apply_inl @[simp] -lemma fromColumns_apply_inr (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (i : m) (j : n₂) : - (fromColumns A₁ A₂) i (Sum.inr j) = A₂ i j := rfl +lemma fromCols_apply_inr (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (i : m) (j : n₂) : + (fromCols A₁ A₂) i (Sum.inr j) = A₂ i j := rfl + +@[deprecated (since := "2024-12-11")] alias fromColumns_apply_inr := fromCols_apply_inr @[simp] lemma toRows₁_apply (A : Matrix (m₁ ⊕ m₂) n R) (i : m₁) (j : n) : @@ -82,26 +89,36 @@ lemma toRows₂_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : toRows₂ (fromRows A₁ A₂) = A₂ := rfl @[simp] -lemma toColumns₁_apply (A : Matrix m (n₁ ⊕ n₂) R) (i : m) (j : n₁) : - (toColumns₁ A) i j = A i (Sum.inl j) := rfl +lemma toCols₁_apply (A : Matrix m (n₁ ⊕ n₂) R) (i : m) (j : n₁) : + (toCols₁ A) i j = A i (Sum.inl j) := rfl + +@[deprecated (since := "2024-12-11")] alias toColumns₁_apply := toCols₁_apply @[simp] -lemma toColumns₂_apply (A : Matrix m (n₁ ⊕ n₂) R) (i : m) (j : n₂) : - (toColumns₂ A) i j = A i (Sum.inr j) := rfl +lemma toCols₂_apply (A : Matrix m (n₁ ⊕ n₂) R) (i : m) (j : n₂) : + (toCols₂ A) i j = A i (Sum.inr j) := rfl + +@[deprecated (since := "2024-12-11")] alias toColumns₂_apply := toCols₂_apply @[simp] -lemma toColumns₁_fromColumns (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : - toColumns₁ (fromColumns A₁ A₂) = A₁ := rfl +lemma toCols₁_fromCols (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : + toCols₁ (fromCols A₁ A₂) = A₁ := rfl + +@[deprecated (since := "2024-12-11")] alias toColumns₁_fromColumns := toCols₁_fromCols @[simp] -lemma toColumns₂_fromColumns (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : - toColumns₂ (fromColumns A₁ A₂) = A₂ := rfl +lemma toCols₂_fromCols (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : + toCols₂ (fromCols A₁ A₂) = A₂ := rfl + +@[deprecated (since := "2024-12-11")] alias toColumns₂_fromColumns := toCols₂_fromCols @[simp] -lemma fromColumns_toColumns (A : Matrix m (n₁ ⊕ n₂) R) : - fromColumns A.toColumns₁ A.toColumns₂ = A := by +lemma fromCols_toCols (A : Matrix m (n₁ ⊕ n₂) R) : + fromCols A.toCols₁ A.toCols₂ = A := by ext i (j | j) <;> simp +@[deprecated (since := "2024-12-11")] alias fromColumns_toColumns := fromCols_toCols + @[simp] lemma fromRows_toRows (A : Matrix (m₁ ⊕ m₂) n R) : fromRows A.toRows₁ A.toRows₂ = A := by ext (i | i) j <;> simp @@ -111,14 +128,18 @@ lemma fromRows_inj : Function.Injective2 (@fromRows R m₁ m₂ n) := by simp only [funext_iff, ← Matrix.ext_iff] aesop -lemma fromColumns_inj : Function.Injective2 (@fromColumns R m n₁ n₂) := by +lemma fromCols_inj : Function.Injective2 (@fromCols R m n₁ n₂) := by intros x1 x2 y1 y2 simp only [funext_iff, ← Matrix.ext_iff] aesop -lemma fromColumns_ext_iff (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (B₁ : Matrix m n₁ R) +@[deprecated (since := "2024-12-11")] alias fromColumns_inj := fromCols_inj + +lemma fromCols_ext_iff (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (B₁ : Matrix m n₁ R) (B₂ : Matrix m n₂ R) : - fromColumns A₁ A₂ = fromColumns B₁ B₂ ↔ A₁ = B₁ ∧ A₂ = B₂ := fromColumns_inj.eq_iff + fromCols A₁ A₂ = fromCols B₁ B₂ ↔ A₁ = B₁ ∧ A₂ = B₂ := fromCols_inj.eq_iff + +@[deprecated (since := "2024-12-11")] alias fromColumns_ext_iff := fromCols_ext_iff lemma fromRows_ext_iff (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B₁ : Matrix m₁ n R) (B₂ : Matrix m₂ n R) : @@ -126,14 +147,16 @@ lemma fromRows_ext_iff (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B₁ : /-- A column partitioned matrix when transposed gives a row partitioned matrix with columns of the initial matrix transposed to become rows. -/ -lemma transpose_fromColumns (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : - transpose (fromColumns A₁ A₂) = fromRows (transpose A₁) (transpose A₂) := by +lemma transpose_fromCols (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : + transpose (fromCols A₁ A₂) = fromRows (transpose A₁) (transpose A₂) := by ext (i | i) j <;> simp +@[deprecated (since := "2024-12-11")] alias transpose_fromColumns := transpose_fromCols + /-- A row partitioned matrix when transposed gives a column partitioned matrix with rows of the initial matrix transposed to become columns. -/ lemma transpose_fromRows (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : - transpose (fromRows A₁ A₂) = fromColumns (transpose A₁) (transpose A₂) := by + transpose (fromRows A₁ A₂) = fromCols (transpose A₁) (transpose A₂) := by ext i (j | j) <;> simp section Neg @@ -148,24 +171,32 @@ lemma fromRows_neg (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : /-- Negating a matrix partitioned by columns is equivalent to negating each of the columns. -/ @[simp] -lemma fromColumns_neg (A₁ : Matrix n m₁ R) (A₂ : Matrix n m₂ R) : - -fromColumns A₁ A₂ = fromColumns (-A₁) (-A₂) := by +lemma fromCols_neg (A₁ : Matrix n m₁ R) (A₂ : Matrix n m₂ R) : + -fromCols A₁ A₂ = fromCols (-A₁) (-A₂) := by ext i (j | j) <;> simp +@[deprecated (since := "2024-12-11")] alias fromColumns_neg := fromCols_neg + end Neg @[simp] -lemma fromColumns_fromRows_eq_fromBlocks (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) +lemma fromCols_fromRows_eq_fromBlocks (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : - fromColumns (fromRows B₁₁ B₂₁) (fromRows B₁₂ B₂₂) = fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ := by + fromCols (fromRows B₁₁ B₂₁) (fromRows B₁₂ B₂₂) = fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ := by ext (_ | _) (_ | _) <;> simp +@[deprecated (since := "2024-12-11")] +alias fromColumns_fromRows_eq_fromBlocks := fromCols_fromRows_eq_fromBlocks + @[simp] -lemma fromRows_fromColumn_eq_fromBlocks (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) +lemma fromRows_fromCols_eq_fromBlocks (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : - fromRows (fromColumns B₁₁ B₁₂) (fromColumns B₂₁ B₂₂) = fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ := by + fromRows (fromCols B₁₁ B₁₂) (fromCols B₂₁ B₂₂) = fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ := by ext (_ | _) (_ | _) <;> simp +@[deprecated (since := "2024-12-11")] +alias fromRows_fromColumn_eq_fromBlocks := fromRows_fromCols_eq_fromBlocks + section Semiring variable [Semiring R] @@ -176,10 +207,12 @@ lemma fromRows_mulVec [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n ext (_ | _) <;> rfl @[simp] -lemma vecMul_fromColumns [Fintype m] (B₁ : Matrix m n₁ R) (B₂ : Matrix m n₂ R) (v : m → R) : - v ᵥ* fromColumns B₁ B₂ = Sum.elim (v ᵥ* B₁) (v ᵥ* B₂) := by +lemma vecMul_fromCols [Fintype m] (B₁ : Matrix m n₁ R) (B₂ : Matrix m n₂ R) (v : m → R) : + v ᵥ* fromCols B₁ B₂ = Sum.elim (v ᵥ* B₁) (v ᵥ* B₂) := by ext (_ | _) <;> rfl +@[deprecated (since := "2024-12-11")] alias vecMul_fromColumns := vecMul_fromCols + @[simp] lemma sum_elim_vecMul_fromRows [Fintype m₁] [Fintype m₂] (B₁ : Matrix m₁ n R) (B₂ : Matrix m₂ n R) (v₁ : m₁ → R) (v₂ : m₂ → R) : @@ -188,11 +221,13 @@ lemma sum_elim_vecMul_fromRows [Fintype m₁] [Fintype m₂] (B₁ : Matrix m₁ simp [Matrix.vecMul, fromRows, dotProduct] @[simp] -lemma fromColumns_mulVec_sum_elim [Fintype n₁] [Fintype n₂] +lemma fromCols_mulVec_sum_elim [Fintype n₁] [Fintype n₂] (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (v₁ : n₁ → R) (v₂ : n₂ → R) : - fromColumns A₁ A₂ *ᵥ Sum.elim v₁ v₂ = A₁ *ᵥ v₁ + A₂ *ᵥ v₂ := by + fromCols A₁ A₂ *ᵥ Sum.elim v₁ v₂ = A₁ *ᵥ v₁ + A₂ *ᵥ v₂ := by ext - simp [Matrix.mulVec, fromColumns] + simp [Matrix.mulVec, fromCols] + +@[deprecated (since := "2024-12-11")] alias fromColumns_mulVec_sum_elim := fromCols_mulVec_sum_elim @[simp] lemma fromRows_mul [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B : Matrix n m R) : @@ -200,42 +235,52 @@ lemma fromRows_mul [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) ext (_ | _) _ <;> simp [mul_apply] @[simp] -lemma mul_fromColumns [Fintype n] (A : Matrix m n R) (B₁ : Matrix n n₁ R) (B₂ : Matrix n n₂ R) : - A * fromColumns B₁ B₂ = fromColumns (A * B₁) (A * B₂) := by +lemma mul_fromCols [Fintype n] (A : Matrix m n R) (B₁ : Matrix n n₁ R) (B₂ : Matrix n n₂ R) : + A * fromCols B₁ B₂ = fromCols (A * B₁) (A * B₂) := by ext _ (_ | _) <;> simp [mul_apply] +@[deprecated (since := "2024-12-11")] alias mul_fromColumns := mul_fromCols + @[simp] lemma fromRows_zero : fromRows (0 : Matrix m₁ n R) (0 : Matrix m₂ n R) = 0 := by ext (_ | _) _ <;> simp @[simp] -lemma fromColumns_zero : fromColumns (0 : Matrix m n₁ R) (0 : Matrix m n₂ R) = 0 := by +lemma fromCols_zero : fromCols (0 : Matrix m n₁ R) (0 : Matrix m n₂ R) = 0 := by ext _ (_ | _) <;> simp +@[deprecated (since := "2024-12-11")] alias fromColumns_zero := fromCols_zero + /-- A row partitioned matrix multiplied by a column partitioned matrix gives a 2 by 2 block matrix. -/ -lemma fromRows_mul_fromColumns [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) +lemma fromRows_mul_fromCols [Fintype n] (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) (B₁ : Matrix n n₁ R) (B₂ : Matrix n n₂ R) : - (fromRows A₁ A₂) * (fromColumns B₁ B₂) = + (fromRows A₁ A₂) * (fromCols B₁ B₂) = fromBlocks (A₁ * B₁) (A₁ * B₂) (A₂ * B₁) (A₂ * B₂) := by ext (_ | _) (_ | _) <;> simp +@[deprecated (since := "2024-12-11")] alias fromRows_mul_fromColumns := fromRows_mul_fromCols + /-- A column partitioned matrix multiplied by a row partitioned matrix gives the sum of the "outer" products of the block matrices. -/ -lemma fromColumns_mul_fromRows [Fintype n₁] [Fintype n₂] (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) +lemma fromCols_mul_fromRows [Fintype n₁] [Fintype n₂] (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) (B₁ : Matrix n₁ n R) (B₂ : Matrix n₂ n R) : - fromColumns A₁ A₂ * fromRows B₁ B₂ = (A₁ * B₁ + A₂ * B₂) := by + fromCols A₁ A₂ * fromRows B₁ B₂ = (A₁ * B₁ + A₂ * B₂) := by ext simp [mul_apply] +@[deprecated (since := "2024-12-11")] alias fromColumns_mul_fromRows := fromCols_mul_fromRows + /-- A column partitioned matrix multipiled by a block matrix results in a column partitioned matrix. -/ -lemma fromColumns_mul_fromBlocks [Fintype m₁] [Fintype m₂] (A₁ : Matrix m m₁ R) (A₂ : Matrix m m₂ R) +lemma fromCols_mul_fromBlocks [Fintype m₁] [Fintype m₂] (A₁ : Matrix m m₁ R) (A₂ : Matrix m m₂ R) (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : - (fromColumns A₁ A₂) * fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ = - fromColumns (A₁ * B₁₁ + A₂ * B₂₁) (A₁ * B₁₂ + A₂ * B₂₂) := by + (fromCols A₁ A₂) * fromBlocks B₁₁ B₁₂ B₂₁ B₂₂ = + fromCols (A₁ * B₁₁ + A₂ * B₂₁) (A₁ * B₁₂ + A₂ * B₂₂) := by ext _ (_ | _) <;> simp [mul_apply] +@[deprecated (since := "2024-12-11")] alias fromColumns_mul_fromBlocks := fromCols_mul_fromBlocks + /-- A block matrix multiplied by a row partitioned matrix gives a row partitioned matrix. -/ lemma fromBlocks_mul_fromRows [Fintype n₁] [Fintype n₂] (A₁ : Matrix n₁ n R) (A₂ : Matrix n₂ n R) (B₁₁ : Matrix m₁ n₁ R) (B₁₂ : Matrix m₁ n₂ R) (B₂₁ : Matrix m₂ n₁ R) (B₂₂ : Matrix m₂ n₂ R) : @@ -252,23 +297,30 @@ variable [CommRing R] /-- Multiplication of a matrix by its inverse is commutative. This is the column and row partitioned matrix form of `Matrix.mul_eq_one_comm`. -The condition `e : n ≃ n₁ ⊕ n₂` states that `fromColumns A₁ A₂` and `fromRows B₁ B₂` are "square". +The condition `e : n ≃ n₁ ⊕ n₂` states that `fromCols A₁ A₂` and `fromRows B₁ B₂` are "square". -/ -lemma fromColumns_mul_fromRows_eq_one_comm +lemma fromCols_mul_fromRows_eq_one_comm [Fintype n₁] [Fintype n₂] [Fintype n] [DecidableEq n] [DecidableEq n₁] [DecidableEq n₂] (e : n ≃ n₁ ⊕ n₂) (A₁ : Matrix n n₁ R) (A₂ : Matrix n n₂ R) (B₁ : Matrix n₁ n R) (B₂ : Matrix n₂ n R) : - fromColumns A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromColumns A₁ A₂ = 1 := + fromCols A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromCols A₁ A₂ = 1 := mul_eq_one_comm_of_equiv e -/-- The lemma `fromColumns_mul_fromRows_eq_one_comm` specialized to the case where the index sets n₁ -and n₂, are the result of subtyping by a predicate and its complement. -/ -lemma equiv_compl_fromColumns_mul_fromRows_eq_one_comm +@[deprecated (since := "2024-12-11")] +alias fromColumns_mul_fromRows_eq_one_comm := fromCols_mul_fromRows_eq_one_comm + +/-- The lemma `fromCols_mul_fromRows_eq_one_comm` specialized to the case where the index sets +`n₁` and `n₂`, are the result of subtyping by a predicate and its complement. -/ +lemma equiv_compl_fromCols_mul_fromRows_eq_one_comm [Fintype n] [DecidableEq n] (p : n → Prop) [DecidablePred p] (A₁ : Matrix n {i // p i} R) (A₂ : Matrix n {i // ¬p i} R) (B₁ : Matrix {i // p i} n R) (B₂ : Matrix {i // ¬p i} n R) : - fromColumns A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromColumns A₁ A₂ = 1 := - fromColumns_mul_fromRows_eq_one_comm (id (Equiv.sumCompl p).symm) A₁ A₂ B₁ B₂ + fromCols A₁ A₂ * fromRows B₁ B₂ = 1 ↔ fromRows B₁ B₂ * fromCols A₁ A₂ = 1 := + fromCols_mul_fromRows_eq_one_comm (id (Equiv.sumCompl p).symm) A₁ A₂ B₁ B₂ + +@[deprecated (since := "2024-12-11")] +alias equiv_compl_fromColumns_mul_fromRows_eq_one_comm := + equiv_compl_fromCols_mul_fromRows_eq_one_comm end CommRing @@ -277,18 +329,26 @@ variable [Star R] /-- A column partitioned matrix in a Star ring when conjugate transposed gives a row partitioned matrix with the columns of the initial matrix conjugate transposed to become rows. -/ -lemma conjTranspose_fromColumns_eq_fromRows_conjTranspose (A₁ : Matrix m n₁ R) +lemma conjTranspose_fromCols_eq_fromRows_conjTranspose (A₁ : Matrix m n₁ R) (A₂ : Matrix m n₂ R) : - conjTranspose (fromColumns A₁ A₂) = fromRows (conjTranspose A₁) (conjTranspose A₂) := by + conjTranspose (fromCols A₁ A₂) = fromRows (conjTranspose A₁) (conjTranspose A₂) := by ext (_ | _) _ <;> simp +@[deprecated (since := "2024-12-11")] +alias conjTranspose_fromColumns_eq_fromRows_conjTranspose := + conjTranspose_fromCols_eq_fromRows_conjTranspose + /-- A row partitioned matrix in a Star ring when conjugate transposed gives a column partitioned matrix with the rows of the initial matrix conjugate transposed to become columns. -/ -lemma conjTranspose_fromRows_eq_fromColumns_conjTranspose (A₁ : Matrix m₁ n R) +lemma conjTranspose_fromRows_eq_fromCols_conjTranspose (A₁ : Matrix m₁ n R) (A₂ : Matrix m₂ n R) : conjTranspose (fromRows A₁ A₂) = - fromColumns (conjTranspose A₁) (conjTranspose A₂) := by + fromCols (conjTranspose A₁) (conjTranspose A₂) := by ext _ (_ | _) <;> simp +@[deprecated (since := "2024-12-11")] +alias conjTranspose_fromRows_eq_fromColumns_conjTranspose := + conjTranspose_fromRows_eq_fromCols_conjTranspose + end Star end Matrix diff --git a/Mathlib/Data/Matrix/ConjTranspose.lean b/Mathlib/Data/Matrix/ConjTranspose.lean index 5aa7f18e50729..5f5843664ca6b 100644 --- a/Mathlib/Data/Matrix/ConjTranspose.lean +++ b/Mathlib/Data/Matrix/ConjTranspose.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Ellen Arlt, Blair Shi, Sean Leather, Mario Carneiro, Johan Commelin, Lu-Ming Zhang -/ import Mathlib.Algebra.BigOperators.GroupWithZero.Action -import Mathlib.Algebra.BigOperators.Pi import Mathlib.Algebra.BigOperators.Ring import Mathlib.Algebra.BigOperators.RingEquiv import Mathlib.Algebra.Module.Pi diff --git a/Mathlib/Data/Matrix/Defs.lean b/Mathlib/Data/Matrix/Defs.lean index 55ae54ad81b76..7767c0b0b6d61 100644 --- a/Mathlib/Data/Matrix/Defs.lean +++ b/Mathlib/Data/Matrix/Defs.lean @@ -320,6 +320,12 @@ def ofAddEquiv [Add α] : (m → n → α) ≃+ Matrix m n α where @[simp] lemma coe_ofAddEquiv_symm [Add α] : ⇑(ofAddEquiv.symm : Matrix m n α ≃+ (m → n → α)) = of.symm := rfl +@[simp] lemma isAddUnit_iff [AddMonoid α] {A : Matrix m n α} : + IsAddUnit A ↔ ∀ i j, IsAddUnit (A i j) := by + simp_rw [isAddUnit_iff_exists, Classical.skolem, forall_and, + ← Matrix.ext_iff, add_apply, zero_apply] + rfl + end Matrix open Matrix diff --git a/Mathlib/Data/Matrix/Diagonal.lean b/Mathlib/Data/Matrix/Diagonal.lean index 6e226513da340..a1ae509a8b378 100644 --- a/Mathlib/Data/Matrix/Diagonal.lean +++ b/Mathlib/Data/Matrix/Diagonal.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Ellen Arlt. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Ellen Arlt, Blair Shi, Sean Leather, Mario Carneiro, Johan Commelin, Lu-Ming Zhang -/ -import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Data.Int.Cast.Pi import Mathlib.Data.Matrix.Defs import Mathlib.Data.Nat.Cast.Basic diff --git a/Mathlib/Data/Matrix/Notation.lean b/Mathlib/Data/Matrix/Notation.lean index 7ff272044152d..a150ccd3763b4 100644 --- a/Mathlib/Data/Matrix/Notation.lean +++ b/Mathlib/Data/Matrix/Notation.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.Group.Fin.Tuple import Mathlib.Data.Matrix.RowCol import Mathlib.Data.Fin.VecNotation import Mathlib.Tactic.FinCases +import Mathlib.Algebra.BigOperators.Fin /-! # Matrix and vector notation @@ -380,9 +381,12 @@ theorem submatrix_updateRow_succAbove (A : Matrix (Fin m.succ) n' α) (v : n' /-- Updating a column then removing it is the same as removing it. -/ @[simp] -theorem submatrix_updateColumn_succAbove (A : Matrix m' (Fin n.succ) α) (v : m' → α) (f : o' → m') - (i : Fin n.succ) : (A.updateColumn i v).submatrix f i.succAbove = A.submatrix f i.succAbove := - ext fun _r s => updateColumn_ne (Fin.succAbove_ne i s) +theorem submatrix_updateCol_succAbove (A : Matrix m' (Fin n.succ) α) (v : m' → α) (f : o' → m') + (i : Fin n.succ) : (A.updateCol i v).submatrix f i.succAbove = A.submatrix f i.succAbove := + ext fun _r s => updateCol_ne (Fin.succAbove_ne i s) + +@[deprecated (since := "2024-12-11")] +alias submatrix_updateColumn_succAbove := submatrix_updateCol_succAbove end Submatrix diff --git a/Mathlib/Data/Matrix/RowCol.lean b/Mathlib/Data/Matrix/RowCol.lean index 43c2b513fbabd..562dd28052b82 100644 --- a/Mathlib/Data/Matrix/RowCol.lean +++ b/Mathlib/Data/Matrix/RowCol.lean @@ -171,9 +171,11 @@ def updateRow [DecidableEq m] (M : Matrix m n α) (i : m) (b : n → α) : Matri of <| Function.update M i b /-- Update, i.e. replace the `j`th column of matrix `A` with the values in `b`. -/ -def updateColumn [DecidableEq n] (M : Matrix m n α) (j : n) (b : m → α) : Matrix m n α := +def updateCol [DecidableEq n] (M : Matrix m n α) (j : n) (b : m → α) : Matrix m n α := of fun i => Function.update (M i) j (b i) +@[deprecated (since := "2024-12-11")] alias updateColumn := updateCol + variable {M : Matrix m n α} {i : m} {j : n} {b : n → α} {c : m → α} @[simp] @@ -182,44 +184,52 @@ theorem updateRow_self [DecidableEq m] : updateRow M i b i = b := Function.update_same (β := fun _ => (n → α)) i b M @[simp] -theorem updateColumn_self [DecidableEq n] : updateColumn M j c i j = c i := +theorem updateCol_self [DecidableEq n] : updateCol M j c i j = c i := -- Porting note: (implicit arg) added `(β := _)` Function.update_same (β := fun _ => α) j (c i) (M i) +@[deprecated (since := "2024-12-11")] alias updateColumn_self := updateCol_self + @[simp] theorem updateRow_ne [DecidableEq m] {i' : m} (i_ne : i' ≠ i) : updateRow M i b i' = M i' := -- Porting note: (implicit arg) added `(β := _)` Function.update_noteq (β := fun _ => (n → α)) i_ne b M @[simp] -theorem updateColumn_ne [DecidableEq n] {j' : n} (j_ne : j' ≠ j) : - updateColumn M j c i j' = M i j' := +theorem updateCol_ne [DecidableEq n] {j' : n} (j_ne : j' ≠ j) : + updateCol M j c i j' = M i j' := -- Porting note: (implicit arg) added `(β := _)` Function.update_noteq (β := fun _ => α) j_ne (c i) (M i) +@[deprecated (since := "2024-12-11")] alias updateColumn_ne := updateCol_ne + theorem updateRow_apply [DecidableEq m] {i' : m} : updateRow M i b i' j = if i' = i then b j else M i' j := by by_cases h : i' = i · rw [h, updateRow_self, if_pos rfl] · rw [updateRow_ne h, if_neg h] -theorem updateColumn_apply [DecidableEq n] {j' : n} : - updateColumn M j c i j' = if j' = j then c i else M i j' := by +theorem updateCol_apply [DecidableEq n] {j' : n} : + updateCol M j c i j' = if j' = j then c i else M i j' := by by_cases h : j' = j - · rw [h, updateColumn_self, if_pos rfl] - · rw [updateColumn_ne h, if_neg h] + · rw [h, updateCol_self, if_pos rfl] + · rw [updateCol_ne h, if_neg h] + +@[deprecated (since := "2024-12-11")] alias updateColumn_apply := updateCol_apply @[simp] -theorem updateColumn_subsingleton [Subsingleton n] (A : Matrix m n R) (i : n) (b : m → R) : - A.updateColumn i b = (col (Fin 1) b).submatrix id (Function.const n 0) := by +theorem updateCol_subsingleton [Subsingleton n] (A : Matrix m n R) (i : n) (b : m → R) : + A.updateCol i b = (col (Fin 1) b).submatrix id (Function.const n 0) := by ext x y - simp [updateColumn_apply, Subsingleton.elim i y] + simp [updateCol_apply, Subsingleton.elim i y] + +@[deprecated (since := "2024-12-11")] alias updateColumn_subsingleton := updateCol_subsingleton @[simp] theorem updateRow_subsingleton [Subsingleton m] (A : Matrix m n R) (i : m) (b : n → R) : A.updateRow i b = (row (Fin 1) b).submatrix (Function.const m 0) id := by ext x y - simp [updateColumn_apply, Subsingleton.elim i x] + simp [updateCol_apply, Subsingleton.elim i x] theorem map_updateRow [DecidableEq m] (f : α → β) : map (updateRow M i b) f = updateRow (M.map f) i (f ∘ b) := by @@ -227,59 +237,70 @@ theorem map_updateRow [DecidableEq m] (f : α → β) : rw [updateRow_apply, map_apply, map_apply, updateRow_apply] exact apply_ite f _ _ _ -theorem map_updateColumn [DecidableEq n] (f : α → β) : - map (updateColumn M j c) f = updateColumn (M.map f) j (f ∘ c) := by +theorem map_updateCol [DecidableEq n] (f : α → β) : + map (updateCol M j c) f = updateCol (M.map f) j (f ∘ c) := by ext - rw [updateColumn_apply, map_apply, map_apply, updateColumn_apply] + rw [updateCol_apply, map_apply, map_apply, updateCol_apply] exact apply_ite f _ _ _ -theorem updateRow_transpose [DecidableEq n] : updateRow Mᵀ j c = (updateColumn M j c)ᵀ := by +@[deprecated (since := "2024-12-11")] alias map_updateColumn := map_updateCol + +theorem updateRow_transpose [DecidableEq n] : updateRow Mᵀ j c = (updateCol M j c)ᵀ := by ext - rw [transpose_apply, updateRow_apply, updateColumn_apply] + rw [transpose_apply, updateRow_apply, updateCol_apply] rfl -theorem updateColumn_transpose [DecidableEq m] : updateColumn Mᵀ i b = (updateRow M i b)ᵀ := by +theorem updateCol_transpose [DecidableEq m] : updateCol Mᵀ i b = (updateRow M i b)ᵀ := by ext - rw [transpose_apply, updateRow_apply, updateColumn_apply] + rw [transpose_apply, updateRow_apply, updateCol_apply] rfl +@[deprecated (since := "2024-12-11")] alias updateColumn_transpose := updateCol_transpose + theorem updateRow_conjTranspose [DecidableEq n] [Star α] : - updateRow Mᴴ j (star c) = (updateColumn M j c)ᴴ := by + updateRow Mᴴ j (star c) = (updateCol M j c)ᴴ := by rw [conjTranspose, conjTranspose, transpose_map, transpose_map, updateRow_transpose, - map_updateColumn] + map_updateCol] rfl -theorem updateColumn_conjTranspose [DecidableEq m] [Star α] : - updateColumn Mᴴ i (star b) = (updateRow M i b)ᴴ := by - rw [conjTranspose, conjTranspose, transpose_map, transpose_map, updateColumn_transpose, +theorem updateCol_conjTranspose [DecidableEq m] [Star α] : + updateCol Mᴴ i (star b) = (updateRow M i b)ᴴ := by + rw [conjTranspose, conjTranspose, transpose_map, transpose_map, updateCol_transpose, map_updateRow] rfl +@[deprecated (since := "2024-12-11")] alias updateColumn_conjTranspose := updateCol_conjTranspose + @[simp] theorem updateRow_eq_self [DecidableEq m] (A : Matrix m n α) (i : m) : A.updateRow i (A i) = A := Function.update_eq_self i A @[simp] -theorem updateColumn_eq_self [DecidableEq n] (A : Matrix m n α) (i : n) : - (A.updateColumn i fun j => A j i) = A := +theorem updateCol_eq_self [DecidableEq n] (A : Matrix m n α) (i : n) : + (A.updateCol i fun j => A j i) = A := funext fun j => Function.update_eq_self i (A j) -theorem diagonal_updateColumn_single [DecidableEq n] [Zero α] (v : n → α) (i : n) (x : α) : - (diagonal v).updateColumn i (Pi.single i x) = diagonal (Function.update v i x) := by +@[deprecated (since := "2024-12-11")] alias updateColumn_eq_self := updateCol_eq_self + +theorem diagonal_updateCol_single [DecidableEq n] [Zero α] (v : n → α) (i : n) (x : α) : + (diagonal v).updateCol i (Pi.single i x) = diagonal (Function.update v i x) := by ext j k obtain rfl | hjk := eq_or_ne j k · rw [diagonal_apply_eq] obtain rfl | hji := eq_or_ne j i - · rw [updateColumn_self, Pi.single_eq_same, Function.update_same] - · rw [updateColumn_ne hji, diagonal_apply_eq, Function.update_noteq hji] + · rw [updateCol_self, Pi.single_eq_same, Function.update_same] + · rw [updateCol_ne hji, diagonal_apply_eq, Function.update_noteq hji] · rw [diagonal_apply_ne _ hjk] obtain rfl | hki := eq_or_ne k i - · rw [updateColumn_self, Pi.single_eq_of_ne hjk] - · rw [updateColumn_ne hki, diagonal_apply_ne _ hjk] + · rw [updateCol_self, Pi.single_eq_of_ne hjk] + · rw [updateCol_ne hki, diagonal_apply_ne _ hjk] + +@[deprecated (since := "2024-12-11")] +alias diagonal_updateColumn_single := diagonal_updateCol_single theorem diagonal_updateRow_single [DecidableEq n] [Zero α] (v : n → α) (i : n) (x : α) : (diagonal v).updateRow i (Pi.single i x) = diagonal (Function.update v i x) := by - rw [← diagonal_transpose, updateRow_transpose, diagonal_updateColumn_single, diagonal_transpose] + rw [← diagonal_transpose, updateRow_transpose, diagonal_updateCol_single, diagonal_transpose] /-! Updating rows and columns commutes in the obvious way with reindexing the matrix. -/ @@ -295,16 +316,22 @@ theorem submatrix_updateRow_equiv [DecidableEq l] [DecidableEq m] (A : Matrix m (A.updateRow i r).submatrix e f = updateRow (A.submatrix e f) (e.symm i) fun i => r (f i) := Eq.trans (by simp_rw [Equiv.apply_symm_apply]) (updateRow_submatrix_equiv A _ _ e f).symm -theorem updateColumn_submatrix_equiv [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : o) - (c : l → α) (e : l ≃ m) (f : o ≃ n) : updateColumn (A.submatrix e f) j c = - (A.updateColumn (f j) fun i => c (e.symm i)).submatrix e f := by +theorem updateCol_submatrix_equiv [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : o) + (c : l → α) (e : l ≃ m) (f : o ≃ n) : updateCol (A.submatrix e f) j c = + (A.updateCol (f j) fun i => c (e.symm i)).submatrix e f := by simpa only [← transpose_submatrix, updateRow_transpose] using congr_arg transpose (updateRow_submatrix_equiv Aᵀ j c f e) -theorem submatrix_updateColumn_equiv [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : n) - (c : m → α) (e : l ≃ m) (f : o ≃ n) : (A.updateColumn j c).submatrix e f = - updateColumn (A.submatrix e f) (f.symm j) fun i => c (e i) := - Eq.trans (by simp_rw [Equiv.apply_symm_apply]) (updateColumn_submatrix_equiv A _ _ e f).symm +@[deprecated (since := "2024-12-11")] +alias updateColumn_submatrix_equiv := updateCol_submatrix_equiv + +theorem submatrix_updateCol_equiv [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : n) + (c : m → α) (e : l ≃ m) (f : o ≃ n) : (A.updateCol j c).submatrix e f = + updateCol (A.submatrix e f) (f.symm j) fun i => c (e i) := + Eq.trans (by simp_rw [Equiv.apply_symm_apply]) (updateCol_submatrix_equiv A _ _ e f).symm + +@[deprecated (since := "2024-12-11")] +alias submatrix_updateColumn_equiv := submatrix_updateCol_equiv /-! `reindex` versions of the above `submatrix` lemmas for convenience. -/ @@ -319,14 +346,18 @@ theorem reindex_updateRow [DecidableEq l] [DecidableEq m] (A : Matrix m n α) (i reindex e f (A.updateRow i r) = updateRow (reindex e f A) (e i) fun i => r (f.symm i) := submatrix_updateRow_equiv _ _ _ _ _ -theorem updateColumn_reindex [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : o) (c : l → α) +theorem updateCol_reindex [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : o) (c : l → α) (e : m ≃ l) (f : n ≃ o) : - updateColumn (reindex e f A) j c = reindex e f (A.updateColumn (f.symm j) fun i => c (e i)) := - updateColumn_submatrix_equiv _ _ _ _ _ + updateCol (reindex e f A) j c = reindex e f (A.updateCol (f.symm j) fun i => c (e i)) := + updateCol_submatrix_equiv _ _ _ _ _ + +@[deprecated (since := "2024-12-11")] alias updateColumn_reindex := updateCol_reindex -theorem reindex_updateColumn [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : n) (c : m → α) +theorem reindex_updateCol [DecidableEq o] [DecidableEq n] (A : Matrix m n α) (j : n) (c : m → α) (e : m ≃ l) (f : n ≃ o) : - reindex e f (A.updateColumn j c) = updateColumn (reindex e f A) (f j) fun i => c (e.symm i) := - submatrix_updateColumn_equiv _ _ _ _ _ + reindex e f (A.updateCol j c) = updateCol (reindex e f A) (f j) fun i => c (e.symm i) := + submatrix_updateCol_equiv _ _ _ _ _ + +@[deprecated (since := "2024-12-11")] alias reindex_updateColumn := reindex_updateCol end Matrix diff --git a/Mathlib/Data/Matroid/Basic.lean b/Mathlib/Data/Matroid/Basic.lean index d3e21b40330bb..a3d760e295283 100644 --- a/Mathlib/Data/Matroid/Basic.lean +++ b/Mathlib/Data/Matroid/Basic.lean @@ -6,6 +6,7 @@ Authors: Peter Nelson import Mathlib.Data.Finite.Prod import Mathlib.Data.Matroid.Init import Mathlib.Data.Set.Card +import Mathlib.Data.Set.Finite.Powerset import Mathlib.Order.Minimal /-! diff --git a/Mathlib/Data/Matroid/Closure.lean b/Mathlib/Data/Matroid/Closure.lean index 4b7a3fddea385..15b24edc449b6 100644 --- a/Mathlib/Data/Matroid/Closure.lean +++ b/Mathlib/Data/Matroid/Closure.lean @@ -5,6 +5,7 @@ Authors: Peter Nelson -/ import Mathlib.Data.Matroid.Restrict import Mathlib.Order.Closure +import Mathlib.Order.CompleteLatticeIntervals /-! # Matroid Closure @@ -176,6 +177,7 @@ lemma Flat.closure (hF : M.Flat F) : M.closure F = F := @[simp] lemma closure_univ (M : Matroid α) : M.closure univ = M.E := by rw [← closure_inter_ground, univ_inter, closure_ground] +@[gcongr] lemma closure_subset_closure (M : Matroid α) (h : X ⊆ Y) : M.closure X ⊆ M.closure Y := subset_sInter (fun _ h' ↦ sInter_subset_of_mem ⟨h'.1, subset_trans (inter_subset_inter_left _ h) h'.2⟩) diff --git a/Mathlib/Data/Matroid/IndepAxioms.lean b/Mathlib/Data/Matroid/IndepAxioms.lean index a1769ebc4fc2f..a18f6951b4618 100644 --- a/Mathlib/Data/Matroid/IndepAxioms.lean +++ b/Mathlib/Data/Matroid/IndepAxioms.lean @@ -3,6 +3,8 @@ Copyright (c) 2023 Peter Nelson. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Peter Nelson -/ +import Mathlib.Order.Interval.Finset.Nat +import Mathlib.Data.Set.Finite.Lattice import Mathlib.Data.Matroid.Basic /-! diff --git a/Mathlib/Data/Multiset/Basic.lean b/Mathlib/Data/Multiset/Basic.lean index e364da53cefec..473e920a37352 100644 --- a/Mathlib/Data/Multiset/Basic.lean +++ b/Mathlib/Data/Multiset/Basic.lean @@ -665,10 +665,7 @@ theorem nsmul_cons {s : Multiset α} (n : ℕ) (a : α) : /-- The cardinality of a multiset is the sum of the multiplicities of all its elements, or simply the length of the underlying list. -/ -def card : Multiset α →+ ℕ where - toFun s := (Quot.liftOn s length) fun _l₁ _l₂ => Perm.length_eq - map_zero' := rfl - map_add' s t := Quotient.inductionOn₂ s t length_append +def card (s : Multiset α) : ℕ := Quot.liftOn s length fun _l₁ _l₂ => Perm.length_eq @[simp] theorem coe_card (l : List α) : card (l : Multiset α) = length l := @@ -682,11 +679,18 @@ theorem length_toList (s : Multiset α) : s.toList.length = card s := by theorem card_zero : @card α 0 = 0 := rfl -theorem card_add (s t : Multiset α) : card (s + t) = card s + card t := - card.map_add s t +@[simp] lemma card_add (s t : Multiset α) : card (s + t) = card s + card t := + Quotient.inductionOn₂ s t length_append -theorem card_nsmul (s : Multiset α) (n : ℕ) : card (n • s) = n * card s := by - rw [card.map_nsmul s n, Nat.nsmul_eq_mul] +/-- `Multiset.card` bundled as a monoid hom. -/ +@[simps] +def cardHom : Multiset α →+ ℕ where + toFun := card + map_zero' := card_zero + map_add' := card_add + +@[simp] +lemma card_nsmul (s : Multiset α) (n : ℕ) : card (n • s) = n * card s := cardHom.map_nsmul .. @[simp] theorem card_cons (a : α) (s : Multiset α) : card (a ::ₘ s) = card s + 1 := @@ -1856,7 +1860,7 @@ theorem filter_add_not (s : Multiset α) : filter p s + filter (fun a => ¬p a) · simp only [add_zero] · simp [Decidable.em, -Bool.not_eq_true, -not_and, not_and_or, or_comm] · simp only [Bool.not_eq_true, decide_eq_true_eq, Bool.eq_false_or_eq_true, - decide_True, implies_true, Decidable.em] + decide_true, implies_true, Decidable.em] theorem filter_map (f : β → α) (s : Multiset β) : filter p (map f s) = map f (filter (p ∘ f) s) := Quot.inductionOn s fun l => by simp [List.filter_map]; rfl diff --git a/Mathlib/Data/NNReal/Defs.lean b/Mathlib/Data/NNReal/Defs.lean index 9c117c2ed6f81..c361f32478764 100644 --- a/Mathlib/Data/NNReal/Defs.lean +++ b/Mathlib/Data/NNReal/Defs.lean @@ -53,7 +53,7 @@ open Function /-- Nonnegative real numbers. -/ def NNReal := { r : ℝ // 0 ≤ r } deriving Zero, One, Semiring, StrictOrderedSemiring, CommMonoidWithZero, CommSemiring, - SemilatticeInf, SemilatticeSup, DistribLattice, OrderedCommSemiring, + PartialOrder, SemilatticeInf, SemilatticeSup, DistribLattice, OrderedCommSemiring, CanonicallyOrderedCommSemiring, Inhabited namespace NNReal diff --git a/Mathlib/Data/Nat/BitIndices.lean b/Mathlib/Data/Nat/BitIndices.lean index 9d9c7c094edad..8c4e3d74b89f5 100644 --- a/Mathlib/Data/Nat/BitIndices.lean +++ b/Mathlib/Data/Nat/BitIndices.lean @@ -114,6 +114,6 @@ theorem two_pow_le_of_mem_bitIndices (ha : a ∈ n.bitIndices) : 2^a ≤ n := by exact List.single_le_sum (by simp) _ <| mem_map_of_mem _ ha theorem not_mem_bitIndices_self (n : ℕ) : n ∉ n.bitIndices := - fun h ↦ (lt_two_pow n).not_le <| two_pow_le_of_mem_bitIndices h + fun h ↦ (n.lt_two_pow_self).not_le <| two_pow_le_of_mem_bitIndices h end Nat diff --git a/Mathlib/Data/Nat/Bitwise.lean b/Mathlib/Data/Nat/Bitwise.lean index e3b32b271b950..cf9e742f04bfc 100644 --- a/Mathlib/Data/Nat/Bitwise.lean +++ b/Mathlib/Data/Nat/Bitwise.lean @@ -51,7 +51,7 @@ lemma bitwise_zero_left (m : Nat) : bitwise f 0 m = if f false true then m else @[simp] lemma bitwise_zero_right (n : Nat) : bitwise f n 0 = if f true false then n else 0 := by unfold bitwise - simp only [ite_self, decide_False, Nat.zero_div, ite_true, ite_eq_right_iff] + simp only [ite_self, decide_false, Nat.zero_div, ite_true, ite_eq_right_iff] rintro ⟨⟩ split_ifs <;> rfl diff --git a/Mathlib/Data/Nat/Cast/Basic.lean b/Mathlib/Data/Nat/Cast/Basic.lean index c494b68c05067..1b66e7d26222f 100644 --- a/Mathlib/Data/Nat/Cast/Basic.lean +++ b/Mathlib/Data/Nat/Cast/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2014 Mario Carneiro. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro -/ -import Mathlib.Algebra.Divisibility.Basic +import Mathlib.Algebra.Divisibility.Hom import Mathlib.Algebra.Group.Even import Mathlib.Algebra.Group.TypeTags.Hom import Mathlib.Algebra.Ring.Hom.Defs diff --git a/Mathlib/Data/Nat/Cast/Defs.lean b/Mathlib/Data/Nat/Cast/Defs.lean index 6ef4845951ac7..b0606a4832ffc 100644 --- a/Mathlib/Data/Nat/Cast/Defs.lean +++ b/Mathlib/Data/Nat/Cast/Defs.lean @@ -166,6 +166,10 @@ theorem binCast_eq [AddMonoidWithOne R] (n : ℕ) : theorem cast_two [AddMonoidWithOne R] : ((2 : ℕ) : R) = (2 : R) := rfl +theorem cast_three [AddMonoidWithOne R] : ((3 : ℕ) : R) = (3 : R) := rfl + +theorem cast_four [AddMonoidWithOne R] : ((4 : ℕ) : R) = (4 : R) := rfl + attribute [simp, norm_cast] Int.natAbs_ofNat end Nat diff --git a/Mathlib/Data/Nat/Choose/Factorization.lean b/Mathlib/Data/Nat/Choose/Factorization.lean index 6bd3a1dac00f3..e639e46d275bf 100644 --- a/Mathlib/Data/Nat/Choose/Factorization.lean +++ b/Mathlib/Data/Nat/Choose/Factorization.lean @@ -39,10 +39,10 @@ theorem factorization_choose_le_log : (choose n k).factorization p ≤ log p n : refine le_of_not_lt fun hnk => h ?_ simp [choose_eq_zero_of_lt hnk] rw [factorization_def _ hp, @padicValNat_def _ ⟨hp⟩ _ (choose_pos hkn)] - rw [← Nat.cast_le (α := ℕ∞), ← multiplicity.Finite.emultiplicity_eq_multiplicity] + rw [← Nat.cast_le (α := ℕ∞), ← FiniteMultiplicity.emultiplicity_eq_multiplicity] · simp only [hp.emultiplicity_choose hkn (lt_add_one _), Nat.cast_le] exact (Finset.card_filter_le _ _).trans (le_of_eq (Nat.card_Ico _ _)) - apply Nat.multiplicity_finite_iff.2 ⟨hp.ne_one, choose_pos hkn⟩ + apply Nat.finiteMultiplicity_iff.2 ⟨hp.ne_one, choose_pos hkn⟩ /-- A `pow` form of `Nat.factorization_choose_le` -/ theorem pow_factorization_choose_le (hn : 0 < n) : p ^ (choose n k).factorization p ≤ n := diff --git a/Mathlib/Data/Nat/Choose/Lucas.lean b/Mathlib/Data/Nat/Choose/Lucas.lean index e3a167ba89664..4e9f92cd773fa 100644 --- a/Mathlib/Data/Nat/Choose/Lucas.lean +++ b/Mathlib/Data/Nat/Choose/Lucas.lean @@ -48,8 +48,8 @@ theorem choose_modEq_choose_mod_mul_choose_div : rw [Prod.mk.injEq] constructor <;> intro h · simp only [mem_product, mem_range] at hx - have h' : x₁ < p := lt_of_lt_of_le hx.left <| mod_lt _ Fin.size_pos' - rw [h, add_mul_mod_self_left, add_mul_div_left _ _ Fin.size_pos', eq_comm (b := x₂)] + have h' : x₁ < p := lt_of_lt_of_le hx.left <| mod_lt _ Fin.pos' + rw [h, add_mul_mod_self_left, add_mul_div_left _ _ Fin.pos', eq_comm (b := x₂)] exact ⟨mod_eq_of_lt h', self_eq_add_left.mpr (div_eq_of_lt h')⟩ · rw [← h.left, ← h.right, mod_add_div] simp only [finset_sum_coeff, coeff_mul_natCast, coeff_X_pow, ite_mul, zero_mul, ← cast_mul] diff --git a/Mathlib/Data/Nat/Count.lean b/Mathlib/Data/Nat/Count.lean index 4d8294ce6bceb..0211381c6106a 100644 --- a/Mathlib/Data/Nat/Count.lean +++ b/Mathlib/Data/Nat/Count.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Vladimir Goryachev, Kyle Miller, Kim Morrison, Eric Rodriguez -/ import Mathlib.SetTheory.Cardinal.Basic +import Mathlib.Algebra.Order.Ring.Nat /-! # Counting on ℕ diff --git a/Mathlib/Data/Nat/Defs.lean b/Mathlib/Data/Nat/Defs.lean index 79583654cc19e..d4a9697c1a97e 100644 --- a/Mathlib/Data/Nat/Defs.lean +++ b/Mathlib/Data/Nat/Defs.lean @@ -438,12 +438,23 @@ protected lemma div_le_div_right (h : a ≤ b) : a / c ≤ b / c := lemma lt_of_div_lt_div (h : a / c < b / c) : a < b := Nat.lt_of_not_le fun hab ↦ Nat.not_le_of_lt h <| Nat.div_le_div_right hab -protected lemma div_pos (hba : b ≤ a) (hb : 0 < b) : 0 < a / b := - Nat.pos_of_ne_zero fun h ↦ Nat.lt_irrefl a <| - calc - a = a % b := by simpa [h] using (mod_add_div a b).symm - _ < b := mod_lt a hb - _ ≤ a := hba +@[simp] protected lemma div_eq_zero_iff : a / b = 0 ↔ b = 0 ∨ a < b where + mp h := by + rw [← mod_add_div a b, h, Nat.mul_zero, Nat.add_zero, or_iff_not_imp_left] + exact mod_lt _ ∘ Nat.pos_iff_ne_zero.2 + mpr := by + obtain rfl | hb := eq_or_ne b 0 + · simp + simp only [hb, false_or] + rw [← Nat.mul_right_inj hb, ← Nat.add_left_cancel_iff, mod_add_div] + simp +contextual [mod_eq_of_lt] + +protected lemma div_ne_zero_iff : a / b ≠ 0 ↔ b ≠ 0 ∧ b ≤ a := by simp + +@[simp] protected lemma div_pos_iff : 0 < a / b ↔ 0 < b ∧ b ≤ a := by + simp [Nat.pos_iff_ne_zero] + +protected lemma div_pos (hba : b ≤ a) (hb : 0 < b) : 0 < a / b := Nat.div_pos_iff.2 ⟨hb, hba⟩ lemma lt_mul_of_div_lt (h : a / c < b) (hc : 0 < c) : a < b * c := Nat.lt_of_not_ge <| Nat.not_le_of_gt h ∘ (Nat.le_div_iff_mul_le hc).2 @@ -622,15 +633,6 @@ lemma le_self_pow (hn : n ≠ 0) : ∀ a : ℕ, a ≤ a ^ n | 0 => zero_le _ | a + 1 => by simpa using Nat.pow_le_pow_right a.succ_pos (Nat.one_le_iff_ne_zero.2 hn) -lemma lt_pow_self (ha : 1 < a) : ∀ n : ℕ, n < a ^ n - | 0 => by simp - | n + 1 => - calc - n + 1 < a ^ n + 1 := Nat.add_lt_add_right (lt_pow_self ha _) _ - _ ≤ a ^ (n + 1) := Nat.pow_lt_pow_succ ha - -lemma lt_two_pow (n : ℕ) : n < 2 ^ n := lt_pow_self (by decide) n - lemma one_le_pow (n m : ℕ) (h : 0 < m) : 1 ≤ m ^ n := by simpa using Nat.pow_le_pow_of_le_left h n lemma one_le_pow' (n m : ℕ) : 1 ≤ (m + 1) ^ n := one_le_pow n (m + 1) (succ_pos m) @@ -653,7 +655,7 @@ lemma one_lt_two_pow' (n : ℕ) : 1 < 2 ^ (n + 1) := one_lt_pow n.succ_ne_zero ( lemma mul_lt_mul_pow_succ (ha : 0 < a) (hb : 1 < b) : n * b < a * b ^ (n + 1) := by rw [Nat.pow_succ, ← Nat.mul_assoc, Nat.mul_lt_mul_right (Nat.lt_trans Nat.zero_lt_one hb)] exact Nat.lt_of_le_of_lt (Nat.le_mul_of_pos_left _ ha) - ((Nat.mul_lt_mul_left ha).2 <| Nat.lt_pow_self hb _) + ((Nat.mul_lt_mul_left ha).2 <| Nat.lt_pow_self hb) lemma sq_sub_sq (a b : ℕ) : a ^ 2 - b ^ 2 = (a + b) * (a - b) := by simpa [Nat.pow_succ] using Nat.mul_self_sub_mul_self_eq a b @@ -1002,17 +1004,6 @@ lemma div_eq_iff_eq_of_dvd_dvd (hn : n ≠ 0) (ha : a ∣ n) (hb : b ∣ n) : n exact Nat.eq_mul_of_div_eq_right ha h · rw [h] -protected lemma div_eq_zero_iff (hb : 0 < b) : a / b = 0 ↔ a < b where - mp h := by rw [← mod_add_div a b, h, Nat.mul_zero, Nat.add_zero]; exact mod_lt _ hb - mpr h := by rw [← Nat.mul_right_inj (Nat.ne_of_gt hb), ← Nat.add_left_cancel_iff, mod_add_div, - mod_eq_of_lt h, Nat.mul_zero, Nat.add_zero] - -protected lemma div_ne_zero_iff (hb : b ≠ 0) : a / b ≠ 0 ↔ b ≤ a := by - rw [ne_eq, Nat.div_eq_zero_iff (Nat.pos_of_ne_zero hb), not_lt] - -protected lemma div_pos_iff (hb : b ≠ 0) : 0 < a / b ↔ b ≤ a := by - rw [Nat.pos_iff_ne_zero, Nat.div_ne_zero_iff hb] - lemma le_iff_ne_zero_of_dvd (ha : a ≠ 0) (hab : a ∣ b) : a ≤ b ↔ b ≠ 0 where mp := by rw [← Nat.pos_iff_ne_zero] at ha ⊢; exact Nat.lt_of_lt_of_le ha mpr hb := Nat.le_of_dvd (Nat.pos_iff_ne_zero.2 hb) hab @@ -1033,7 +1024,7 @@ lemma not_pos_pow_dvd : ∀ {a n : ℕ} (_ : 1 < a) (_ : 1 < n), ¬ a ^ n ∣ a have : succ a * succ a ^ n ∣ succ a * 1 := by simpa [pow_succ'] using h have : succ a ^ n ∣ 1 := Nat.dvd_of_mul_dvd_mul_left (succ_pos _) this have he : succ a ^ n = 1 := eq_one_of_dvd_one this - have : n < succ a ^ n := lt_pow_self hp n + have : n < succ a ^ n := n.lt_pow_self hp have : n < 1 := by rwa [he] at this have : n = 0 := Nat.eq_zero_of_le_zero <| le_of_lt_succ this have : 1 < 1 := by rwa [this] at hk @@ -1041,7 +1032,7 @@ lemma not_pos_pow_dvd : ∀ {a n : ℕ} (_ : 1 < a) (_ : 1 < n), ¬ a ^ n ∣ a lemma lt_of_pow_dvd_right (hb : b ≠ 0) (ha : 2 ≤ a) (h : a ^ n ∣ b) : n < b := by rw [← Nat.pow_lt_pow_iff_right (succ_le_iff.1 ha)] - exact Nat.lt_of_le_of_lt (le_of_dvd (Nat.pos_iff_ne_zero.2 hb) h) (lt_pow_self ha _) + exact Nat.lt_of_le_of_lt (le_of_dvd (Nat.pos_iff_ne_zero.2 hb) h) (Nat.lt_pow_self ha) lemma div_dvd_of_dvd (h : n ∣ m) : m / n ∣ m := ⟨n, (Nat.div_mul_cancel h).symm⟩ @@ -1275,7 +1266,7 @@ lemma dvd_mul_of_div_dvd (h : b ∣ a) (hdiv : a / b ∣ c) : a ∣ b * c := by /-- If a small natural number is divisible by a larger natural number, the small number is zero. -/ lemma eq_zero_of_dvd_of_lt (w : a ∣ b) (h : b < a) : b = 0 := - Nat.eq_zero_of_dvd_of_div_eq_zero w ((Nat.div_eq_zero_iff (lt_of_le_of_lt (zero_le b) h)).mpr h) + Nat.eq_zero_of_dvd_of_div_eq_zero w (by simp [h]) lemma le_of_lt_add_of_dvd (h : a < b + n) : n ∣ a → n ∣ b → a ≤ b := by rintro ⟨a, rfl⟩ ⟨b, rfl⟩ diff --git a/Mathlib/Data/Nat/Digits.lean b/Mathlib/Data/Nat/Digits.lean index f9385aca645c1..5adc574882628 100644 --- a/Mathlib/Data/Nat/Digits.lean +++ b/Mathlib/Data/Nat/Digits.lean @@ -304,8 +304,8 @@ theorem digits_len (b n : ℕ) (hb : 1 < b) (hn : n ≠ 0) : (b.digits n).length induction' n using Nat.strong_induction_on with n IH rw [digits_eq_cons_digits_div hb hn, List.length] by_cases h : n / b = 0 - · have hb0 : b ≠ 0 := (Nat.succ_le_iff.1 hb).ne_bot - simp [h, log_eq_zero_iff, ← Nat.div_eq_zero_iff hb0.bot_lt] + · simp [IH, h] + aesop · have : n / b < n := div_lt_self (Nat.pos_of_ne_zero hn) hb rw [IH _ this h, log_div_base, tsub_add_cancel_of_le] refine Nat.succ_le_of_lt (log_pos hb ?_) @@ -821,8 +821,7 @@ theorem digits_one (b n) (n0 : 0 < n) (nb : n < b) : Nat.digits b n = [n] ∧ 1 have b2 : 1 < b := lt_iff_add_one_le.mpr (le_trans (add_le_add_right (lt_iff_add_one_le.mp n0) 1) nb) refine ⟨?_, b2, n0⟩ - rw [Nat.digits_def' b2 n0, Nat.mod_eq_of_lt nb, - (Nat.div_eq_zero_iff ((zero_le n).trans_lt nb)).2 nb, Nat.digits_zero] + rw [Nat.digits_def' b2 n0, Nat.mod_eq_of_lt nb, Nat.div_eq_zero_iff.2 <| .inr nb, Nat.digits_zero] /- Porting note: this part of the file is tactic related. diff --git a/Mathlib/Data/Nat/Factorial/BigOperators.lean b/Mathlib/Data/Nat/Factorial/BigOperators.lean index 56a55af7e4af1..606f5b7c49b2d 100644 --- a/Mathlib/Data/Nat/Factorial/BigOperators.lean +++ b/Mathlib/Data/Nat/Factorial/BigOperators.lean @@ -33,6 +33,10 @@ theorem prod_factorial_dvd_factorial_sum : (∏ i ∈ s, (f i)!) ∣ (∑ i ∈ · rw [prod_cons, Finset.sum_cons] exact (mul_dvd_mul_left _ ih).trans (Nat.factorial_mul_factorial_dvd_factorial_add _ _) +theorem ascFactorial_eq_prod_range (n : ℕ) : ∀ k, n.ascFactorial k = ∏ i ∈ range k, (n + i) + | 0 => rfl + | k + 1 => by rw [ascFactorial, prod_range_succ, mul_comm, ascFactorial_eq_prod_range n k] + theorem descFactorial_eq_prod_range (n : ℕ) : ∀ k, n.descFactorial k = ∏ i ∈ range k, (n - i) | 0 => rfl | k + 1 => by rw [descFactorial, prod_range_succ, mul_comm, descFactorial_eq_prod_range n k] diff --git a/Mathlib/Data/Nat/Factorization/Basic.lean b/Mathlib/Data/Nat/Factorization/Basic.lean index 4e4bd0fa951c0..a56075aac773f 100644 --- a/Mathlib/Data/Nat/Factorization/Basic.lean +++ b/Mathlib/Data/Nat/Factorization/Basic.lean @@ -155,7 +155,7 @@ theorem ordCompl_mul (a b p : ℕ) : ordCompl[p] (a * b) = ordCompl[p] a * ordCo theorem factorization_lt {n : ℕ} (p : ℕ) (hn : n ≠ 0) : n.factorization p < n := by by_cases pp : p.Prime · exact (Nat.pow_lt_pow_iff_right pp.one_lt).1 <| (ordProj_le p hn).trans_lt <| - lt_pow_self pp.one_lt _ + Nat.lt_pow_self pp.one_lt · simpa only [factorization_eq_zero_of_non_prime n pp] using hn.bot_lt /-- An upper bound on `n.factorization p` -/ @@ -270,7 +270,7 @@ and `n'` such that `n'` is not divisible by `p` and `n = p^e * n'`. -/ theorem exists_eq_pow_mul_and_not_dvd {n : ℕ} (hn : n ≠ 0) (p : ℕ) (hp : p ≠ 1) : ∃ e n' : ℕ, ¬p ∣ n' ∧ n = p ^ e * n' := let ⟨a', h₁, h₂⟩ := - (Nat.multiplicity_finite_iff.mpr ⟨hp, Nat.pos_of_ne_zero hn⟩).exists_eq_pow_mul_and_not_dvd + (Nat.finiteMultiplicity_iff.mpr ⟨hp, Nat.pos_of_ne_zero hn⟩).exists_eq_pow_mul_and_not_dvd ⟨_, a', h₂, h₁⟩ /-- Any nonzero natural number is the product of an odd part `m` and a power of @@ -284,7 +284,7 @@ theorem dvd_iff_div_factorization_eq_tsub {d n : ℕ} (hd : d ≠ 0) (hdn : d d ∣ n ↔ (n / d).factorization = n.factorization - d.factorization := by refine ⟨factorization_div, ?_⟩ rcases eq_or_lt_of_le hdn with (rfl | hd_lt_n); · simp - have h1 : n / d ≠ 0 := fun H => Nat.lt_asymm hd_lt_n ((Nat.div_eq_zero_iff hd.bot_lt).mp H) + have h1 : n / d ≠ 0 := by simp [*] intro h rw [dvd_iff_le_div_mul n d] by_contra h2 @@ -356,7 +356,7 @@ theorem dvd_iff_prime_pow_dvd_dvd (n d : ℕ) : · simp rcases eq_or_ne d 0 with (rfl | hd) · simp only [zero_dvd_iff, hn, false_iff, not_forall] - exact ⟨2, n, prime_two, dvd_zero _, mt (le_of_dvd hn.bot_lt) (lt_two_pow n).not_le⟩ + exact ⟨2, n, prime_two, dvd_zero _, mt (le_of_dvd hn.bot_lt) (n.lt_two_pow_self).not_le⟩ refine ⟨fun h p k _ hpkd => dvd_trans hpkd h, ?_⟩ rw [← factorization_prime_le_iff_dvd hd hn] intro h p pp diff --git a/Mathlib/Data/Nat/Factors.lean b/Mathlib/Data/Nat/Factors.lean index 5d4c83169c971..67bf2864fa197 100644 --- a/Mathlib/Data/Nat/Factors.lean +++ b/Mathlib/Data/Nat/Factors.lean @@ -37,7 +37,7 @@ def primeFactorsList : ℕ → List ℕ | k + 2 => let m := minFac (k + 2) m :: primeFactorsList ((k + 2) / m) -decreasing_by show (k + 2) / m < (k + 2); exact factors_lemma +decreasing_by exact factors_lemma @[deprecated (since := "2024-06-14")] alias factors := primeFactorsList diff --git a/Mathlib/Data/Nat/Log.lean b/Mathlib/Data/Nat/Log.lean index 1d16748dda19e..b2e55d35fe599 100644 --- a/Mathlib/Data/Nat/Log.lean +++ b/Mathlib/Data/Nat/Log.lean @@ -123,7 +123,7 @@ theorem lt_pow_of_log_lt {b x y : ℕ} (hb : 1 < b) : log b y < x → y < b ^ x lemma log_lt_self (b : ℕ) {x : ℕ} (hx : x ≠ 0) : log b x < x := match le_or_lt b 1 with | .inl h => log_of_left_le_one h x ▸ Nat.pos_iff_ne_zero.2 hx - | .inr h => log_lt_of_lt_pow hx <| lt_pow_self h _ + | .inr h => log_lt_of_lt_pow hx <| Nat.lt_pow_self h lemma log_le_self (b x : ℕ) : log b x ≤ x := if hx : x = 0 then by simp [hx] diff --git a/Mathlib/Data/Nat/Multiplicity.lean b/Mathlib/Data/Nat/Multiplicity.lean index 77e18051deac1..ece38a314c41c 100644 --- a/Mathlib/Data/Nat/Multiplicity.lean +++ b/Mathlib/Data/Nat/Multiplicity.lean @@ -46,7 +46,7 @@ Legendre, p-adic -/ -open Finset Nat multiplicity +open Finset Nat open Nat @@ -57,7 +57,7 @@ divides `n`. This set is expressed by filtering `Ico 1 b` where `b` is any bound `log m n`. -/ theorem emultiplicity_eq_card_pow_dvd {m n b : ℕ} (hm : m ≠ 1) (hn : 0 < n) (hb : log m n < b) : emultiplicity m n = #{i ∈ Ico 1 b | m ^ i ∣ n} := - have fin := Nat.multiplicity_finite_iff.2 ⟨hm, hn⟩ + have fin := Nat.finiteMultiplicity_iff.2 ⟨hm, hn⟩ calc emultiplicity m n = #(Ico 1 <| multiplicity m n + 1) := by simp [fin.emultiplicity_eq_multiplicity] @@ -91,7 +91,7 @@ theorem emultiplicity_pow {p m n : ℕ} (hp : p.Prime) : _root_.emultiplicity_pow hp.prime theorem emultiplicity_self {p : ℕ} (hp : p.Prime) : emultiplicity p p = 1 := - (Nat.multiplicity_finite_iff.2 ⟨hp.ne_one, hp.pos⟩).emultiplicity_self + (Nat.finiteMultiplicity_iff.2 ⟨hp.ne_one, hp.pos⟩).emultiplicity_self theorem emultiplicity_pow_self {p n : ℕ} (hp : p.Prime) : emultiplicity p (p ^ n) = n := _root_.emultiplicity_pow_self hp.ne_zero hp.prime.not_unit n @@ -136,7 +136,7 @@ theorem emultiplicity_factorial_mul_succ {n p : ℕ} (hp : p.Prime) : have h2 : p * n + 1 ≤ p * (n + 1) := by linarith have h3 : p * n + 1 ≤ p * (n + 1) + 1 := by omega have hm : emultiplicity p (p * n)! ≠ ⊤ := by - rw [Ne, emultiplicity_eq_top, Classical.not_not, Nat.multiplicity_finite_iff] + rw [Ne, emultiplicity_eq_top, Classical.not_not, Nat.finiteMultiplicity_iff] exact ⟨hp.ne_one, factorial_pos _⟩ revert hm have h4 : ∀ m ∈ Ico (p * n + 1) (p * (n + 1)), emultiplicity p m = 0 := by @@ -201,8 +201,8 @@ theorem emultiplicity_choose' {p n k b : ℕ} (hp : p.Prime) (hnb : log p (n + k (add_comm n k ▸ hnb)), multiplicity_choose_aux hp (le_add_left k n)] simp [add_comm] refine (WithTop.add_right_cancel_iff ?_).1 h₁ - apply finite_iff_emultiplicity_ne_top.1 - exact Nat.multiplicity_finite_iff.2 ⟨hp.ne_one, mul_pos (factorial_pos k) (factorial_pos n)⟩ + apply finiteMultiplicity_iff_emultiplicity_ne_top.1 + exact Nat.finiteMultiplicity_iff.2 ⟨hp.ne_one, mul_pos (factorial_pos k) (factorial_pos n)⟩ /-- The multiplicity of `p` in `choose n k` is the number of carries when `k` and `n - k` are added in base `p`. The set is expressed by filtering `Ico 1 b` where `b` @@ -251,8 +251,8 @@ theorem emultiplicity_choose_prime_pow {p n k : ℕ} (hp : p.Prime) (hkn : k ≤ emultiplicity p (choose (p ^ n) k) = ↑(n - multiplicity p k) := by push_cast rw [← emultiplicity_choose_prime_pow_add_emultiplicity hp hkn hk0, - (multiplicity_finite_iff.2 ⟨hp.ne_one, Nat.pos_of_ne_zero hk0⟩).emultiplicity_eq_multiplicity, - (multiplicity_finite_iff.2 ⟨hp.ne_one, choose_pos hkn⟩).emultiplicity_eq_multiplicity] + (finiteMultiplicity_iff.2 ⟨hp.ne_one, Nat.pos_of_ne_zero hk0⟩).emultiplicity_eq_multiplicity, + (finiteMultiplicity_iff.2 ⟨hp.ne_one, choose_pos hkn⟩).emultiplicity_eq_multiplicity] norm_cast rw [Nat.add_sub_cancel_right] diff --git a/Mathlib/Data/Nat/Prime/Basic.lean b/Mathlib/Data/Nat/Prime/Basic.lean index 1802c6c89eab8..68d16200182d3 100644 --- a/Mathlib/Data/Nat/Prime/Basic.lean +++ b/Mathlib/Data/Nat/Prime/Basic.lean @@ -51,14 +51,7 @@ theorem Prime.five_le_of_ne_two_of_ne_three {p : ℕ} (hp : p.Prime) (h_two : p (h_three : p ≠ 3) : 5 ≤ p := by by_contra! h revert h_two h_three hp - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - match p with - | 0 => decide - | 1 => decide - | 2 => decide - | 3 => decide - | 4 => decide - | n + 5 => exact (h.not_le <| le_add_left ..).elim + decide +revert end diff --git a/Mathlib/Data/Nat/Prime/Int.lean b/Mathlib/Data/Nat/Prime/Int.lean index f4fc6f0359bbe..d357a3d303050 100644 --- a/Mathlib/Data/Nat/Prime/Int.lean +++ b/Mathlib/Data/Nat/Prime/Int.lean @@ -9,7 +9,7 @@ import Mathlib.Data.Nat.Prime.Basic /-! # Prime numbers in the naturals and the integers -TODO: This file can probably be merged with `Data/Nat/Int/NatPrime.lean`. +TODO: This file can probably be merged with `Mathlib/Data/Int/NatPrime.lean`. -/ diff --git a/Mathlib/Data/Nat/Squarefree.lean b/Mathlib/Data/Nat/Squarefree.lean index 53bb8bb29fec5..b1463cae82ce5 100644 --- a/Mathlib/Data/Nat/Squarefree.lean +++ b/Mathlib/Data/Nat/Squarefree.lean @@ -50,7 +50,7 @@ theorem _root_.Squarefree.natFactorization_le_one {n : ℕ} (p : ℕ) (hn : Squa n.factorization p ≤ 1 := by rcases eq_or_ne n 0 with (rfl | hn') · simp - rw [multiplicity.squarefree_iff_emultiplicity_le_one] at hn + rw [squarefree_iff_emultiplicity_le_one] at hn by_cases hp : p.Prime · have := hn p rw [← multiplicity_eq_factorization hp hn'] @@ -387,8 +387,7 @@ lemma primeFactors_prod (hs : ∀ p ∈ s, p.Prime) : primeFactors (∏ p ∈ s, lemma primeFactors_div_gcd (hm : Squarefree m) (hn : n ≠ 0) : primeFactors (m / m.gcd n) = primeFactors m \ primeFactors n := by ext p - have : m / m.gcd n ≠ 0 := - (Nat.div_ne_zero_iff <| gcd_ne_zero_right hn).2 <| gcd_le_left _ hm.ne_zero.bot_lt + have : m / m.gcd n ≠ 0 := by simp [gcd_ne_zero_right hn, gcd_le_left _ hm.ne_zero.bot_lt] simp only [mem_primeFactors, ne_eq, this, not_false_eq_true, and_true, not_and, mem_sdiff, hm.ne_zero, hn, dvd_div_iff_mul_dvd (gcd_dvd_left _ _)] refine ⟨fun hp ↦ ⟨⟨hp.1, dvd_of_mul_left_dvd hp.2⟩, fun _ hpn ↦ hp.1.not_unit <| hm _ <| diff --git a/Mathlib/Data/Num/Basic.lean b/Mathlib/Data/Num/Basic.lean index 07f592d41ee94..54c9466d8c312 100644 --- a/Mathlib/Data/Num/Basic.lean +++ b/Mathlib/Data/Num/Basic.lean @@ -159,10 +159,10 @@ instance : LT PosNum := instance : LE PosNum := ⟨fun a b => ¬b < a⟩ -instance decidableLT : @DecidableRel PosNum (· < ·) +instance decidableLT : DecidableRel (α := PosNum) (· < ·) | a, b => by dsimp [LT.lt]; infer_instance -instance decidableLE : @DecidableRel PosNum (· ≤ ·) +instance decidableLE : DecidableRel (α := PosNum) (· ≤ ·) | a, b => by dsimp [LE.le]; infer_instance end PosNum @@ -270,10 +270,10 @@ instance : LT Num := instance : LE Num := ⟨fun a b => ¬b < a⟩ -instance decidableLT : @DecidableRel Num (· < ·) +instance decidableLT : DecidableRel (α := Num) (· < ·) | a, b => by dsimp [LT.lt]; infer_instance -instance decidableLE : @DecidableRel Num (· ≤ ·) +instance decidableLE : DecidableRel (α := Num) (· ≤ ·) | a, b => by dsimp [LE.le]; infer_instance /-- Converts a `Num` to a `ZNum`. -/ @@ -479,10 +479,10 @@ instance : LT ZNum := instance : LE ZNum := ⟨fun a b => ¬b < a⟩ -instance decidableLT : @DecidableRel ZNum (· < ·) +instance decidableLT : DecidableRel (α := ZNum) (· < ·) | a, b => by dsimp [LT.lt]; infer_instance -instance decidableLE : @DecidableRel ZNum (· ≤ ·) +instance decidableLE : DecidableRel (α := ZNum) (· ≤ ·) | a, b => by dsimp [LE.le]; infer_instance end ZNum diff --git a/Mathlib/Data/Num/Bitwise.lean b/Mathlib/Data/Num/Bitwise.lean index b374f02e13946..57703e62a4600 100644 --- a/Mathlib/Data/Num/Bitwise.lean +++ b/Mathlib/Data/Num/Bitwise.lean @@ -409,7 +409,7 @@ end SNum namespace SNum /-- `a.bits n` is the vector of the `n` first bits of `a` (starting from the LSB). -/ -def bits : SNum → ∀ n, Vector Bool n +def bits : SNum → ∀ n, Mathlib.Vector Bool n | _, 0 => Vector.nil | p, n + 1 => head p ::ᵥ bits (tail p) n diff --git a/Mathlib/Data/Ordmap/Ordnode.lean b/Mathlib/Data/Ordmap/Ordnode.lean index c4c775f222f1b..430a9571c3dbc 100644 --- a/Mathlib/Data/Ordmap/Ordnode.lean +++ b/Mathlib/Data/Ordmap/Ordnode.lean @@ -366,7 +366,7 @@ and should always be used instead of `Amem`. -/ def Amem [LE α] (x : α) : Ordnode α → Prop := Any fun y => x ≤ y ∧ y ≤ x -instance Amem.decidable [LE α] [@DecidableRel α (· ≤ ·)] (x : α) : +instance Amem.decidable [LE α] [DecidableRel (α := α) (· ≤ ·)] (x : α) : ∀ t, Decidable (Amem x t) := by dsimp [Amem]; infer_instance @@ -807,7 +807,7 @@ def ofAscList : List α → Ordnode α section -variable [LE α] [@DecidableRel α (· ≤ ·)] +variable [LE α] [DecidableRel (α := α) (· ≤ ·)] /-- O(log n). Does the set (approximately) contain the element `x`? That is, is there an element that is equivalent to `x` in the order? @@ -1220,7 +1220,7 @@ Equivalent elements are selected with a preference for smaller source elements. image (fun x ↦ x + 2) {1, 2, 4} = {3, 4, 6} image (fun x : ℕ ↦ x - 2) {1, 2, 4} = {0, 2} -/ -def image {α β} [LE β] [@DecidableRel β (· ≤ ·)] (f : α → β) (t : Ordnode α) : Ordnode β := +def image {α β} [LE β] [DecidableRel (α := β) (· ≤ ·)] (f : α → β) (t : Ordnode α) : Ordnode β := ofList (t.toList.map f) end diff --git a/Mathlib/Data/Ordmap/Ordset.lean b/Mathlib/Data/Ordmap/Ordset.lean index c2343c28c9c36..e1d9a4f8ef4b9 100644 --- a/Mathlib/Data/Ordmap/Ordset.lean +++ b/Mathlib/Data/Ordmap/Ordset.lean @@ -491,7 +491,7 @@ theorem equiv_iff {t₁ t₂ : Ordnode α} (h₁ : Sized t₁) (h₂ : Sized t /-! ### `mem` -/ -theorem pos_size_of_mem [LE α] [@DecidableRel α (· ≤ ·)] {x : α} {t : Ordnode α} (h : Sized t) +theorem pos_size_of_mem [LE α] [DecidableRel (α := α) (· ≤ ·)] {x : α} {t : Ordnode α} (h : Sized t) (h_mem : x ∈ t) : 0 < size t := by cases t; · { contradiction }; · { simp [h.1] } /-! ### `(find/erase/split)(Min/Max)` -/ @@ -564,7 +564,7 @@ theorem merge_node {ls ll lx lr rs rl rx rr} : /-! ### `insert` -/ -theorem dual_insert [Preorder α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) : +theorem dual_insert [Preorder α] [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (x : α) : ∀ t : Ordnode α, dual (Ordnode.insert x t) = @Ordnode.insert αᵒᵈ _ _ x (dual t) | nil => rfl | node _ l y r => by @@ -1317,7 +1317,7 @@ theorem Valid.merge {l r} (hl : Valid l) (hr : Valid r) (sep : l.All fun x => r.All fun y => x < y) : Valid (@merge α l r) := (Valid'.merge_aux hl hr sep).1 -theorem insertWith.valid_aux [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (f : α → α) (x : α) +theorem insertWith.valid_aux [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (f : α → α) (x : α) (hf : ∀ y, x ≤ y ∧ y ≤ x → x ≤ f y ∧ f y ≤ x) : ∀ {t o₁ o₂}, Valid' o₁ t o₂ → @@ -1346,28 +1346,28 @@ theorem insertWith.valid_aux [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ exact (e.add_left _).add_right _ exact Or.inr ⟨_, e, h.3.1⟩ -theorem insertWith.valid [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (f : α → α) (x : α) +theorem insertWith.valid [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (f : α → α) (x : α) (hf : ∀ y, x ≤ y ∧ y ≤ x → x ≤ f y ∧ f y ≤ x) {t} (h : Valid t) : Valid (insertWith f x t) := (insertWith.valid_aux _ _ hf h ⟨⟩ ⟨⟩).1 -theorem insert_eq_insertWith [@DecidableRel α (· ≤ ·)] (x : α) : +theorem insert_eq_insertWith [DecidableRel (α := α) (· ≤ ·)] (x : α) : ∀ t, Ordnode.insert x t = insertWith (fun _ => x) x t | nil => rfl | node _ l y r => by unfold Ordnode.insert insertWith; cases cmpLE x y <;> simp [insert_eq_insertWith] -theorem insert.valid [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) {t} (h : Valid t) : +theorem insert.valid [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (x : α) {t} (h : Valid t) : Valid (Ordnode.insert x t) := by rw [insert_eq_insertWith]; exact insertWith.valid _ _ (fun _ _ => ⟨le_rfl, le_rfl⟩) h -theorem insert'_eq_insertWith [@DecidableRel α (· ≤ ·)] (x : α) : +theorem insert'_eq_insertWith [DecidableRel (α := α) (· ≤ ·)] (x : α) : ∀ t, insert' x t = insertWith id x t | nil => rfl | node _ l y r => by unfold insert' insertWith; cases cmpLE x y <;> simp [insert'_eq_insertWith] -theorem insert'.valid [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) {t} (h : Valid t) : - Valid (insert' x t) := by +theorem insert'.valid [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] + (x : α) {t} (h : Valid t) : Valid (insert' x t) := by rw [insert'_eq_insertWith]; exact insertWith.valid _ _ (fun _ => id) h theorem Valid'.map_aux {β} [Preorder β] {f : α → β} (f_strict_mono : StrictMono f) {t a₁ a₂} @@ -1404,7 +1404,7 @@ theorem map.valid {β} [Preorder β] {f : α → β} (f_strict_mono : StrictMono Valid (map f t) := (Valid'.map_aux f_strict_mono h).1 -theorem Valid'.erase_aux [@DecidableRel α (· ≤ ·)] (x : α) {t a₁ a₂} (h : Valid' a₁ t a₂) : +theorem Valid'.erase_aux [DecidableRel (α := α) (· ≤ ·)] (x : α) {t a₁ a₂} (h : Valid' a₁ t a₂) : Valid' a₁ (erase x t) a₂ ∧ Raised (erase x t).size t.size := by induction t generalizing a₁ a₂ with | nil => @@ -1438,10 +1438,10 @@ theorem Valid'.erase_aux [@DecidableRel α (· ≤ ·)] (x : α) {t a₁ a₂} ( exact t_r_size right; exists t_r.size; exact And.intro t_r_size h.bal.1 -theorem erase.valid [@DecidableRel α (· ≤ ·)] (x : α) {t} (h : Valid t) : Valid (erase x t) := +theorem erase.valid [DecidableRel (α := α) (· ≤ ·)] (x : α) {t} (h : Valid t) : Valid (erase x t) := (Valid'.erase_aux x h).1 -theorem size_erase_of_mem [@DecidableRel α (· ≤ ·)] {x : α} {t a₁ a₂} (h : Valid' a₁ t a₂) +theorem size_erase_of_mem [DecidableRel (α := α) (· ≤ ·)] {x : α} {t a₁ a₂} (h : Valid' a₁ t a₂) (h_mem : x ∈ t) : size (erase x t) = size t - 1 := by induction t generalizing a₁ a₂ with | nil => @@ -1528,22 +1528,22 @@ instance Empty.instDecidablePred : DecidablePred (@Empty α _) := /-- O(log n). Insert an element into the set, preserving balance and the BST property. If an equivalent element is already in the set, this replaces it. -/ -protected def insert [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) (s : Ordset α) : +protected def insert [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (x : α) (s : Ordset α) : Ordset α := ⟨Ordnode.insert x s.1, insert.valid _ s.2⟩ -instance instInsert [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] : Insert α (Ordset α) := +instance instInsert [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] : Insert α (Ordset α) := ⟨Ordset.insert⟩ /-- O(log n). Insert an element into the set, preserving balance and the BST property. If an equivalent element is already in the set, the set is returned as is. -/ -nonrec def insert' [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) (s : Ordset α) : +nonrec def insert' [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (x : α) (s : Ordset α) : Ordset α := ⟨insert' x s.1, insert'.valid _ s.2⟩ section -variable [@DecidableRel α (· ≤ ·)] +variable [DecidableRel (α := α) (· ≤ ·)] /-- O(log n). Does the set contain the element `x`? That is, is there an element that is equivalent to `x` in the order? -/ @@ -1570,7 +1570,7 @@ end /-- O(log n). Remove an element from the set equivalent to `x`. Does nothing if there is no such element. -/ -def erase [@DecidableRel α (· ≤ ·)] (x : α) (s : Ordset α) : Ordset α := +def erase [DecidableRel (α := α) (· ≤ ·)] (x : α) (s : Ordset α) : Ordset α := ⟨Ordnode.erase x s.val, Ordnode.erase.valid x s.property⟩ /-- O(n). Map a function across a tree, without changing the structure. -/ diff --git a/Mathlib/Data/PNat/Defs.lean b/Mathlib/Data/PNat/Defs.lean index afc7437cfeddc..f1b5d5d414da3 100644 --- a/Mathlib/Data/PNat/Defs.lean +++ b/Mathlib/Data/PNat/Defs.lean @@ -4,8 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Neil Strickland -/ import Mathlib.Data.Nat.Defs +import Mathlib.Data.PNat.Notation import Mathlib.Order.Basic -import Mathlib.Order.TypeTags import Mathlib.Tactic.Coe import Mathlib.Tactic.Lift import Mathlib.Data.Int.Order.Basic diff --git a/Mathlib/Data/PNat/Notation.lean b/Mathlib/Data/PNat/Notation.lean new file mode 100644 index 0000000000000..be4a3da696f59 --- /dev/null +++ b/Mathlib/Data/PNat/Notation.lean @@ -0,0 +1,27 @@ +/- +Copyright (c) 2018 Mario Carneiro. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Mario Carneiro, Simon Hudon, Yury Kudryashov +-/ + +import Mathlib.Data.Nat.Notation + +/-! # Definition and notation for positive natural numbers -/ + +/-- `ℕ+` is the type of positive natural numbers. It is defined as a subtype, + and the VM representation of `ℕ+` is the same as `ℕ` because the proof + is not stored. -/ +def PNat := { n : ℕ // 0 < n } deriving DecidableEq + +@[inherit_doc] +notation "ℕ+" => PNat + +/-- The underlying natural number -/ +@[coe] +def PNat.val : ℕ+ → ℕ := Subtype.val + +instance coePNatNat : Coe ℕ+ ℕ := + ⟨PNat.val⟩ + +instance : Repr ℕ+ := + ⟨fun n n' => reprPrec n.1 n'⟩ diff --git a/Mathlib/Data/Quot.lean b/Mathlib/Data/Quot.lean index 9508faa6a1ad6..ccad963fe4394 100644 --- a/Mathlib/Data/Quot.lean +++ b/Mathlib/Data/Quot.lean @@ -79,8 +79,8 @@ protected def hrecOn₂ (qa : Quot ra) (qb : Quot rb) (f : ∀ a b, φ ⟦a⟧ /-- Map a function `f : α → β` such that `ra x y` implies `rb (f x) (f y)` to a map `Quot ra → Quot rb`. -/ -protected def map (f : α → β) (h : (ra ⇒ rb) f f) : Quot ra → Quot rb := - (Quot.lift fun x ↦ ⟦f x⟧) fun x y (h₁ : ra x y) ↦ Quot.sound <| h h₁ +protected def map (f : α → β) (h : ∀ ⦃a b : α⦄, ra a b → rb (f a) (f b)) : Quot ra → Quot rb := + Quot.lift (fun x => Quot.mk rb (f x)) fun _ _ hra ↦ Quot.sound <| h hra /-- If `ra` is a subrelation of `ra'`, then we have a natural map `Quot ra → Quot ra'`. -/ protected def mapRight {ra' : α → α → Prop} (h : ∀ a₁ a₂, ra a₁ a₂ → ra' a₁ a₂) : @@ -227,11 +227,11 @@ protected def hrecOn₂ (qa : Quotient sa) (qb : Quotient sb) (f : ∀ a b, φ /-- Map a function `f : α → β` that sends equivalent elements to equivalent elements to a function `Quotient sa → Quotient sb`. Useful to define unary operations on quotients. -/ -protected def map (f : α → β) (h : ((· ≈ ·) ⇒ (· ≈ ·)) f f) : Quotient sa → Quotient sb := +protected def map (f : α → β) (h : ∀ ⦃a b : α⦄, a ≈ b → f a ≈ f b) : Quotient sa → Quotient sb := Quot.map f h @[simp] -theorem map_mk (f : α → β) (h : ((· ≈ ·) ⇒ (· ≈ ·)) f f) (x : α) : +theorem map_mk (f : α → β) (h) (x : α) : Quotient.map f h (⟦x⟧ : Quotient sa) = (⟦f x⟧ : Quotient sb) := rfl @@ -240,12 +240,13 @@ variable {γ : Sort*} {sc : Setoid γ} /-- Map a function `f : α → β → γ` that sends equivalent elements to equivalent elements to a function `f : Quotient sa → Quotient sb → Quotient sc`. Useful to define binary operations on quotients. -/ -protected def map₂ (f : α → β → γ) (h : ((· ≈ ·) ⇒ (· ≈ ·) ⇒ (· ≈ ·)) f f) : +protected def map₂ (f : α → β → γ) + (h : ∀ ⦃a₁ a₂⦄, a₁ ≈ a₂ → ∀ ⦃b₁ b₂⦄, b₁ ≈ b₂ → f a₁ b₁ ≈ f a₂ b₂) : Quotient sa → Quotient sb → Quotient sc := Quotient.lift₂ (fun x y ↦ ⟦f x y⟧) fun _ _ _ _ h₁ h₂ ↦ Quot.sound <| h h₁ h₂ @[simp] -theorem map₂_mk (f : α → β → γ) (h : ((· ≈ ·) ⇒ (· ≈ ·) ⇒ (· ≈ ·)) f f) (x : α) (y : β) : +theorem map₂_mk (f : α → β → γ) (h) (x : α) (y : β) : Quotient.map₂ f h (⟦x⟧ : Quotient sa) (⟦y⟧ : Quotient sb) = (⟦f x y⟧ : Quotient sc) := rfl @@ -693,7 +694,8 @@ theorem hrecOn₂'_mk'' {φ : Quotient s₁ → Quotient s₂ → Sort*} /-- Map a function `f : α → β` that sends equivalent elements to equivalent elements to a function `Quotient sa → Quotient sb`. Useful to define unary operations on quotients. -/ -protected def map' (f : α → β) (h : (s₁.r ⇒ s₂.r) f f) : Quotient s₁ → Quotient s₂ := +protected def map' (f : α → β) (h : ∀ a b, s₁.r a b → s₂.r (f a) (f b)) : + Quotient s₁ → Quotient s₂ := Quot.map f h @[simp] @@ -702,15 +704,7 @@ theorem map'_mk'' (f : α → β) (h) (x : α) : rfl /-- A version of `Quotient.map₂` using curly braces and unification. -/ -protected def map₂' (f : α → β → γ) (h : (s₁.r ⇒ s₂.r ⇒ s₃.r) f f) : - Quotient s₁ → Quotient s₂ → Quotient s₃ := - Quotient.map₂ f h - -@[simp] -theorem map₂'_mk'' (f : α → β → γ) (h) (x : α) : - (Quotient.mk'' x : Quotient s₁).map₂' f h = - (Quotient.map' (f x) (h (Setoid.refl x)) : Quotient s₂ → Quotient s₃) := - rfl +@[deprecated (since := "2024-12-01")] protected alias map₂' := Quotient.map₂ theorem exact' {a b : α} : (Quotient.mk'' a : Quotient s₁) = Quotient.mk'' b → s₁ a b := diff --git a/Mathlib/Data/Rat/Denumerable.lean b/Mathlib/Data/Rat/Denumerable.lean index 9a1494cd76969..116e03e72a7dd 100644 --- a/Mathlib/Data/Rat/Denumerable.lean +++ b/Mathlib/Data/Rat/Denumerable.lean @@ -3,9 +3,9 @@ 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.CharZero.Infinite -import Mathlib.Algebra.Ring.Rat +import Mathlib.Algebra.Order.Ring.Rat import Mathlib.Data.Rat.Encodable +import Mathlib.Algebra.CharZero.Infinite import Mathlib.Logic.Denumerable /-! @@ -13,7 +13,7 @@ import Mathlib.Logic.Denumerable This file proves that ℚ is denumerable. -The fact that ℚ has cardinality ℵ₀ is proved in `Data.Rat.Cardinal` +The fact that ℚ has cardinality ℵ₀ is proved in `Mathlib.Data.Rat.Cardinal` -/ assert_not_exists Module diff --git a/Mathlib/Data/Rat/Floor.lean b/Mathlib/Data/Rat/Floor.lean index 7b67abd634887..a916bde474c7d 100644 --- a/Mathlib/Data/Rat/Floor.lean +++ b/Mathlib/Data/Rat/Floor.lean @@ -50,6 +50,11 @@ instance : FloorRing ℚ := protected theorem floor_def {q : ℚ} : ⌊q⌋ = q.num / q.den := Rat.floor_def' q +protected theorem ceil_def (q : ℚ) : ⌈q⌉ = -(-q.num / ↑q.den) := by + change -⌊-q⌋ = _ + rw [Rat.floor_def, num_neg_eq_neg_num, den_neg_eq_den] + + @[norm_cast] theorem floor_intCast_div_natCast (n : ℤ) (d : ℕ) : ⌊(↑n / ↑d : ℚ)⌋ = n / (↑d : ℤ) := by rw [Rat.floor_def] @@ -63,10 +68,19 @@ theorem floor_intCast_div_natCast (n : ℤ) (d : ℕ) : ⌊(↑n / ↑d : ℚ) refine (Int.mul_ediv_mul_of_pos _ _ <| pos_of_mul_pos_left ?_ <| Int.natCast_nonneg q.den).symm rwa [← d_eq_c_mul_denom, Int.natCast_pos] +@[norm_cast] +theorem ceil_intCast_div_natCast (n : ℤ) (d : ℕ) : ⌈(↑n / ↑d : ℚ)⌉ = -((-n) / (↑d : ℤ)) := by + conv_lhs => rw [← neg_neg ⌈_⌉, ← floor_neg] + rw [← neg_div, ← Int.cast_neg, floor_intCast_div_natCast] + @[norm_cast] theorem floor_natCast_div_natCast (n d : ℕ) : ⌊(↑n / ↑d : ℚ)⌋ = n / d := floor_intCast_div_natCast n d +@[norm_cast] +theorem ceil_natCast_div_natCast (n d : ℕ) : ⌈(↑n / ↑d : ℚ)⌉ = -((-n) / d) := + ceil_intCast_div_natCast n d + @[norm_cast] theorem natFloor_natCast_div_natCast (n d : ℕ) : ⌊(↑n / ↑d : ℚ)⌋₊ = n / d := by rw [← Int.ofNat_inj, Int.natCast_floor_eq_floor (by positivity)] @@ -128,10 +142,46 @@ def evalIntFloor : NormNumExt where eval {u αZ} e := do let _i ← synthInstanceQ q(LinearOrderedField $α) assertInstancesCommute have z : Q(ℤ) := mkRawIntLit ⌊q⌋ - letI : $z =Q ⌊$n / $d⌋ := ⟨⟩ + letI : $z =Q $n / $d := ⟨⟩ return .isInt q(inferInstance) z ⌊q⌋ q(isInt_intFloor_ofIsRat _ $n $d $h) | _, _, _ => failure +theorem isNat_intCeil {R} [LinearOrderedRing R] [FloorRing R] (r : R) (m : ℕ) : + IsNat r m → IsNat ⌈r⌉ m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩ + +theorem isInt_intCeil {R} [LinearOrderedRing R] [FloorRing R] (r : R) (m : ℤ) : + IsInt r m → IsInt ⌈r⌉ m := by rintro ⟨⟨⟩⟩; exact ⟨by simp⟩ + +theorem isInt_intCeil_ofIsRat (r : α) (n : ℤ) (d : ℕ) : + IsRat r n d → IsInt ⌈r⌉ (-(-n / d)) := by + rintro ⟨inv, rfl⟩ + constructor + simp only [invOf_eq_inv, ← div_eq_mul_inv, Int.cast_id] + rw [← ceil_intCast_div_natCast n d, ← ceil_cast (α := α), Rat.cast_div, + cast_intCast, cast_natCast] + +/-- `norm_num` extension for `Int.ceil` -/ +@[norm_num ⌈_⌉] +def evalIntCeil : NormNumExt where eval {u αZ} e := do + match u, αZ, e with + | 0, ~q(ℤ), ~q(@Int.ceil $α $instR $instF $x) => + match ← derive x with + | .isBool .. => failure + | .isNat _ _ pb => do + assertInstancesCommute + return .isNat q(inferInstance) _ q(isNat_intCeil $x _ $pb) + | .isNegNat _ _ pb => do + assertInstancesCommute + -- ceil always keeps naturals negative, so we can shortcut `.isInt` + return .isNegNat q(inferInstance) _ q(isInt_intCeil _ _ $pb) + | .isRat _ q n d h => do + let _i ← synthInstanceQ q(LinearOrderedField $α) + assertInstancesCommute + have z : Q(ℤ) := mkRawIntLit ⌈q⌉ + letI : $z =Q (-(-$n / $d)) := ⟨⟩ + return .isInt q(inferInstance) z ⌈q⌉ q(isInt_intCeil_ofIsRat _ $n $d $h) + | _, _, _ => failure + end NormNum end Rat diff --git a/Mathlib/Data/Real/GoldenRatio.lean b/Mathlib/Data/Real/GoldenRatio.lean index 2518fadf3188a..dc7a2c207b503 100644 --- a/Mathlib/Data/Real/GoldenRatio.lean +++ b/Mathlib/Data/Real/GoldenRatio.lean @@ -3,10 +3,11 @@ Copyright (c) 2020 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker, Alexey Soloyev, Junyan Xu, Kamila Szewczyk -/ -import Mathlib.Data.Real.Irrational -import Mathlib.Data.Nat.Fib.Basic -import Mathlib.Data.Fin.VecNotation +import Mathlib.Algebra.EuclideanDomain.Basic import Mathlib.Algebra.LinearRecurrence +import Mathlib.Data.Fin.VecNotation +import Mathlib.Data.Nat.Fib.Basic +import Mathlib.Data.Real.Irrational import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.Prime diff --git a/Mathlib/Data/Real/Irrational.lean b/Mathlib/Data/Real/Irrational.lean index 59bde31ad0787..12f99f0fcb687 100644 --- a/Mathlib/Data/Real/Irrational.lean +++ b/Mathlib/Data/Real/Irrational.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne, Yury Kudryashov -/ import Mathlib.Algebra.Algebra.Rat +import Mathlib.Data.Nat.Prime.Int import Mathlib.Data.Rat.Sqrt import Mathlib.Data.Real.Sqrt -import Mathlib.RingTheory.Algebraic -import Mathlib.RingTheory.Int.Basic +import Mathlib.RingTheory.Algebraic.Basic import Mathlib.Tactic.IntervalCases /-! @@ -25,7 +25,7 @@ but this only works if you `unseal Nat.sqrt.iter in` before the theorem where yo -/ -open Rat Real multiplicity +open Rat Real /-- A real number is irrational if it is not equal to any rational number. -/ def Irrational (x : ℝ) := @@ -79,7 +79,7 @@ theorem irrational_nrt_of_n_not_dvd_multiplicity {x : ℝ} (n : ℕ) {m : ℤ} ( rw [← Int.cast_pow, Int.cast_inj] at hxr subst m have : y ≠ 0 := by rintro rfl; rw [zero_pow hnpos.ne'] at hm; exact hm rfl - rw [(Int.multiplicity_finite_iff.2 ⟨by simp [hp.1.ne_one], this⟩).multiplicity_pow + rw [(Int.finiteMultiplicity_iff.2 ⟨by simp [hp.1.ne_one], this⟩).multiplicity_pow (Nat.prime_iff_prime_int.1 hp.1), Nat.mul_mod_right] at hv exact hv rfl diff --git a/Mathlib/Data/Real/Pi/Irrational.lean b/Mathlib/Data/Real/Pi/Irrational.lean index afebb88a105b2..34d2652435e86 100644 --- a/Mathlib/Data/Real/Pi/Irrational.lean +++ b/Mathlib/Data/Real/Pi/Irrational.lean @@ -91,7 +91,7 @@ private lemma recursion' (n : ℕ) : ring have hv₂ (x) : HasDerivAt v₂ (v₂' x) x := (hasDerivAt_mul_const θ).cos convert_to (∫ (x : ℝ) in (-1)..1, u₁ x * v₁' x) * θ = _ using 1 - · simp_rw [u₁, v₁', ← intervalIntegral.integral_mul_const, sq θ, mul_assoc] + · simp_rw [u₁, v₁', f, ← intervalIntegral.integral_mul_const, sq θ, mul_assoc] rw [integral_mul_deriv_eq_deriv_mul (fun x _ => hu₁ x) (fun x _ => hv₁ x) (hu₁d.intervalIntegrable _ _) (hv₁d.intervalIntegrable _ _), hu₁_eval_one, hu₁_eval_neg_one, zero_mul, zero_mul, sub_zero, zero_sub, ← integral_neg, ← integral_mul_const] diff --git a/Mathlib/Data/Seq/Seq.lean b/Mathlib/Data/Seq/Seq.lean index 76e8c653427c3..8b25a1d0c7c0a 100644 --- a/Mathlib/Data/Seq/Seq.lean +++ b/Mathlib/Data/Seq/Seq.lean @@ -376,7 +376,7 @@ theorem coinduction2 (s) (f g : Seq α → Seq β) @[coe] def ofList (l : List α) : Seq α := ⟨List.get? l, fun {n} h => by - rw [List.get?_eq_none] at h ⊢ + rw [List.get?_eq_none_iff] at h ⊢ exact h.trans (Nat.le_succ n)⟩ instance coeList : Coe (List α) (Seq α) := diff --git a/Mathlib/Data/Set/Basic.lean b/Mathlib/Data/Set/Basic.lean index 8d28bac27f0b0..ae281b9e0c8a5 100644 --- a/Mathlib/Data/Set/Basic.lean +++ b/Mathlib/Data/Set/Basic.lean @@ -1007,7 +1007,6 @@ def subtypeInsertEquivOption /-! ### Lemmas about singletons -/ -/- porting note: instance was in core in Lean3 -/ instance : LawfulSingleton α (Set α) := ⟨fun x => Set.ext fun a => by simp only [mem_empty_iff_false, mem_insert_iff, or_false] diff --git a/Mathlib/Data/Set/Card.lean b/Mathlib/Data/Set/Card.lean index e6992277d23f0..56ac372f3623f 100644 --- a/Mathlib/Data/Set/Card.lean +++ b/Mathlib/Data/Set/Card.lean @@ -10,7 +10,7 @@ import Mathlib.SetTheory.Cardinal.Finite We define the cardinality of set `s` as a term `Set.encard s : ℕ∞` and a term `Set.ncard s : ℕ`. The latter takes the junk value of zero if `s` is infinite. Both functions are noncomputable, and -are defined in terms of `PartENat.card` (which takes a type as its argument); this file can be seen +are defined in terms of `ENat.card` (which takes a type as its argument); this file can be seen as an API for the same function in the special case where the type is a coercion of a `Set`, allowing for smoother interactions with the `Set` API. @@ -59,19 +59,18 @@ namespace Set variable {α β : Type*} {s t : Set α} /-- The cardinality of a set as a term in `ℕ∞` -/ -noncomputable def encard (s : Set α) : ℕ∞ := PartENat.withTopEquiv (PartENat.card s) +noncomputable def encard (s : Set α) : ℕ∞ := ENat.card s @[simp] theorem encard_univ_coe (s : Set α) : encard (univ : Set s) = encard s := by - rw [encard, encard, PartENat.card_congr (Equiv.Set.univ ↑s)] + rw [encard, encard, ENat.card_congr (Equiv.Set.univ ↑s)] theorem encard_univ (α : Type*) : - encard (univ : Set α) = PartENat.withTopEquiv (PartENat.card α) := by - rw [encard, PartENat.card_congr (Equiv.Set.univ α)] + encard (univ : Set α) = ENat.card α := by + rw [encard, ENat.card_congr (Equiv.Set.univ α)] theorem Finite.encard_eq_coe_toFinset_card (h : s.Finite) : s.encard = h.toFinset.card := by have := h.fintype - rw [encard, PartENat.card_eq_coe_fintype_card, - PartENat.withTopEquiv_natCast, toFinite_toFinset, toFinset_card] + rw [encard, ENat.card_eq_coe_fintype_card, toFinite_toFinset, toFinset_card] theorem encard_eq_coe_toFinset_card (s : Set α) [Fintype s] : encard s = s.toFinset.card := by have h := toFinite s @@ -83,13 +82,10 @@ theorem encard_eq_coe_toFinset_card (s : Set α) [Fintype s] : encard s = s.toFi theorem Infinite.encard_eq {s : Set α} (h : s.Infinite) : s.encard = ⊤ := by have := h.to_subtype - rw [encard, ← PartENat.withTopEquiv.symm.injective.eq_iff, Equiv.symm_apply_apply, - PartENat.withTopEquiv_symm_top, PartENat.card_eq_top_of_infinite] + rw [encard, ENat.card_eq_top_of_infinite] @[simp] theorem encard_eq_zero : s.encard = 0 ↔ s = ∅ := by - rw [encard, ← PartENat.withTopEquiv.symm.injective.eq_iff, Equiv.symm_apply_apply, - PartENat.withTopEquiv_symm_zero, PartENat.card_eq_zero_iff_empty, isEmpty_subtype, - eq_empty_iff_forall_not_mem] + rw [encard, ENat.card_eq_zero_iff_empty, isEmpty_subtype, eq_empty_iff_forall_not_mem] @[simp] theorem encard_empty : (∅ : Set α).encard = 0 := by rw [encard_eq_zero] @@ -106,12 +102,11 @@ theorem encard_ne_zero : s.encard ≠ 0 ↔ s.Nonempty := by protected alias ⟨_, Nonempty.encard_pos⟩ := encard_pos @[simp] theorem encard_singleton (e : α) : ({e} : Set α).encard = 1 := by - rw [encard, ← PartENat.withTopEquiv.symm.injective.eq_iff, Equiv.symm_apply_apply, - PartENat.card_eq_coe_fintype_card, Fintype.card_ofSubsingleton, Nat.cast_one]; rfl + rw [encard, ENat.card_eq_coe_fintype_card, Fintype.card_ofSubsingleton, Nat.cast_one] theorem encard_union_eq (h : Disjoint s t) : (s ∪ t).encard = s.encard + t.encard := by classical - simp [encard, PartENat.card_congr (Equiv.Set.union h), PartENat.card_sum, PartENat.withTopEquiv] + simp [encard, ENat.card_congr (Equiv.Set.union h)] theorem encard_insert_of_not_mem {a : α} (has : a ∉ s) : (insert a s).encard = s.encard + 1 := by rw [← union_singleton, encard_union_eq (by simpa), encard_singleton] @@ -381,10 +376,10 @@ section Function variable {s : Set α} {t : Set β} {f : α → β} theorem InjOn.encard_image (h : InjOn f s) : (f '' s).encard = s.encard := by - rw [encard, PartENat.card_image_of_injOn h, encard] + rw [encard, ENat.card_image_of_injOn h, encard] theorem encard_congr (e : s ≃ t) : s.encard = t.encard := by - rw [← encard_univ_coe, ← encard_univ_coe t, encard_univ, encard_univ, PartENat.card_congr e] + rw [← encard_univ_coe, ← encard_univ_coe t, encard_univ, encard_univ, ENat.card_congr e] theorem _root_.Function.Injective.encard_image (hf : f.Injective) (s : Set α) : (f '' s).encard = s.encard := @@ -767,8 +762,8 @@ theorem surj_on_of_inj_on_of_ncard_le {t : Set β} (f : ∀ a ∈ s, β) (hf : have hft' := Fintype.ofInjective f' finj set f'' : ∀ a, a ∈ s.toFinset → β := fun a h ↦ f a (by simpa using h) convert @Finset.surj_on_of_inj_on_of_card_le _ _ _ t.toFinset f'' _ _ _ _ (by simpa) using 1 - · simp - · simp [hf] + · simp [f''] + · simp [f'', hf] · intros a₁ a₂ ha₁ ha₂ h rw [mem_toFinset] at ha₁ ha₂ exact hinj _ _ ha₁ ha₂ h diff --git a/Mathlib/Data/Set/Lattice.lean b/Mathlib/Data/Set/Lattice.lean index 41676f753e553..b77cd5d86cdec 100644 --- a/Mathlib/Data/Set/Lattice.lean +++ b/Mathlib/Data/Set/Lattice.lean @@ -924,10 +924,12 @@ theorem sUnion_powerset_gc : gc_sSup_Iic /-- `⋃₀` and `𝒫` form a Galois insertion. -/ -def sUnion_powerset_gi : +def sUnionPowersetGI : GaloisInsertion (⋃₀ · : Set (Set α) → Set α) (𝒫 · : Set α → Set (Set α)) := gi_sSup_Iic +@[deprecated (since := "2024-12-07")] alias sUnion_powerset_gi := sUnionPowersetGI + /-- If all sets in a collection are either `∅` or `Set.univ`, then so is their union. -/ theorem sUnion_mem_empty_univ {S : Set (Set α)} (h : S ⊆ {∅, univ}) : ⋃₀ S ∈ ({∅, univ} : Set (Set α)) := by diff --git a/Mathlib/Data/Set/List.lean b/Mathlib/Data/Set/List.lean index 60839e4f416e6..0d3cf309c7743 100644 --- a/Mathlib/Data/Set/List.lean +++ b/Mathlib/Data/Set/List.lean @@ -41,8 +41,10 @@ theorem range_list_get : range l.get = { x | x ∈ l } := by theorem range_list_get? : range l.get? = insert none (some '' { x | x ∈ l }) := by rw [← range_list_get, ← 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 _⟩] + · exact (le_or_lt l.length n).imp get?_eq_none_iff.mpr + (fun hlt => ⟨⟨_, hlt⟩, (get?_eq_get hlt).symm⟩) + · exact ⟨_, get?_eq_none_iff.mpr le_rfl⟩ + · exact range_subset_iff.2 fun k => ⟨_, get?_eq_get _⟩ @[simp] theorem range_list_getD (d : α) : (range fun n : Nat => l[n]?.getD d) = insert d { x | x ∈ l } := diff --git a/Mathlib/Data/Set/NAry.lean b/Mathlib/Data/Set/NAry.lean index 72515c986a918..5596fbcdcce5c 100644 --- a/Mathlib/Data/Set/NAry.lean +++ b/Mathlib/Data/Set/NAry.lean @@ -49,13 +49,17 @@ theorem image_subset_image2_left (hb : b ∈ t) : (fun a => f a b) '' s ⊆ imag theorem image_subset_image2_right (ha : a ∈ s) : f a '' t ⊆ image2 f s t := forall_mem_image.2 fun _ => mem_image2_of_mem ha -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, hx, y, hy, rfl⟩, fun h _ ⟨x, hx, y, hy, hz⟩ => hz ▸ h x hx y hy⟩ +lemma forall_mem_image2 {p : γ → Prop} : + (∀ z ∈ image2 f s t, p z) ↔ ∀ x ∈ s, ∀ y ∈ t, p (f x y) := by aesop + +lemma exists_mem_image2 {p : γ → Prop} : + (∃ z ∈ image2 f s t, p z) ↔ ∃ x ∈ s, ∃ y ∈ t, p (f x y) := by aesop + +@[deprecated (since := "2024-11-23")] alias forall_image2_iff := forall_mem_image2 @[simp] theorem image2_subset_iff {u : Set γ} : image2 f s t ⊆ u ↔ ∀ x ∈ s, ∀ y ∈ t, f x y ∈ u := - forall_image2_iff + forall_mem_image2 theorem image2_subset_iff_left : image2 f s t ⊆ u ↔ ∀ a ∈ s, (fun b => f a b) '' t ⊆ u := by simp_rw [image2_subset_iff, image_subset_iff, subset_def, mem_preimage] @@ -190,7 +194,7 @@ 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) := - eq_of_forall_subset_iff fun _ ↦ by simp only [image2_subset_iff, forall_image2_iff, h_assoc] + eq_of_forall_subset_iff fun _ ↦ by simp only [image2_subset_iff, forall_mem_image2, h_assoc] theorem image2_comm {g : β → α → γ} (h_comm : ∀ a b, f a b = g b a) : image2 f s t = image2 g t s := (image2_swap _ _ _).trans <| by simp_rw [h_comm] diff --git a/Mathlib/Data/Set/Sups.lean b/Mathlib/Data/Set/Sups.lean index 9c2fe8ef24b07..e9bca4723383e 100644 --- a/Mathlib/Data/Set/Sups.lean +++ b/Mathlib/Data/Set/Sups.lean @@ -90,7 +90,7 @@ theorem image_subset_sups_right : a ∈ s → (· ⊔ ·) a '' t ⊆ s ⊻ t := image_subset_image2_right theorem forall_sups_iff {p : α → Prop} : (∀ c ∈ s ⊻ t, p c) ↔ ∀ a ∈ s, ∀ b ∈ t, p (a ⊔ b) := - forall_image2_iff + forall_mem_image2 @[simp] theorem sups_subset_iff : s ⊻ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊔ b ∈ u := @@ -220,7 +220,7 @@ theorem image_subset_infs_right : a ∈ s → (a ⊓ ·) '' t ⊆ s ⊼ t := image_subset_image2_right theorem forall_infs_iff {p : α → Prop} : (∀ c ∈ s ⊼ t, p c) ↔ ∀ a ∈ s, ∀ b ∈ t, p (a ⊓ b) := - forall_image2_iff + forall_mem_image2 @[simp] theorem infs_subset_iff : s ⊼ t ⊆ u ↔ ∀ a ∈ s, ∀ b ∈ t, a ⊓ b ∈ u := diff --git a/Mathlib/Data/Setoid/Basic.lean b/Mathlib/Data/Setoid/Basic.lean index bbaa5b239fbfe..3599ac45fefc2 100644 --- a/Mathlib/Data/Setoid/Basic.lean +++ b/Mathlib/Data/Setoid/Basic.lean @@ -19,7 +19,7 @@ The complete lattice instance for equivalence relations could have been defined the Galois insertion of equivalence relations on α into binary relations on α, and then using `CompleteLattice.copy` to define a complete lattice instance with more appropriate definitional equalities (a similar example is `Filter.CompleteLattice` in -`Order/Filter/Basic.lean`). This does not save space, however, and is less clear. +`Mathlib/Order/Filter/Basic.lean`). This does not save space, however, and is less clear. Partitions are not defined as a separate structure here; users are encouraged to reason about them using the existing `Setoid` and its infrastructure. @@ -133,7 +133,7 @@ equivalence relations. -/ @[simps] def prodQuotientEquiv (r : Setoid α) (s : Setoid β) : Quotient r × Quotient s ≃ Quotient (r.prod s) where - toFun := fun (x, y) ↦ Quotient.map₂' Prod.mk (fun _ _ hx _ _ hy ↦ ⟨hx, hy⟩) x y + toFun := fun (x, y) ↦ Quotient.map₂ Prod.mk (fun _ _ hx _ _ hy ↦ ⟨hx, hy⟩) x y invFun := fun q ↦ Quotient.liftOn' q (fun xy ↦ (Quotient.mk'' xy.1, Quotient.mk'' xy.2)) fun x y hxy ↦ Prod.ext (by simpa using hxy.1) (by simpa using hxy.2) left_inv := fun q ↦ by diff --git a/Mathlib/Data/Setoid/Partition.lean b/Mathlib/Data/Setoid/Partition.lean index 1aa847fee7ff8..ddc6a2e70e0d9 100644 --- a/Mathlib/Data/Setoid/Partition.lean +++ b/Mathlib/Data/Setoid/Partition.lean @@ -166,7 +166,7 @@ noncomputable def quotientEquivClasses (r : Setoid α) : Quotient r ≃ Setoid.c · intro (q_a : Quotient r) (q_b : Quotient r) h_eq induction' q_a using Quotient.ind with a induction' q_b using Quotient.ind with b - simp only [Subtype.ext_iff, Quotient.lift_mk, Subtype.ext_iff] at h_eq + simp only [f, Quotient.lift_mk, Subtype.ext_iff] at h_eq apply Quotient.sound show a ∈ { x | r x b } rw [← h_eq] diff --git a/Mathlib/Data/Sign.lean b/Mathlib/Data/Sign.lean index a2065300b0e34..55941cf1dae35 100644 --- a/Mathlib/Data/Sign.lean +++ b/Mathlib/Data/Sign.lean @@ -122,7 +122,13 @@ instance : BoundedOrder SignType where top := 1 le_top := LE.of_pos bot := -1 - bot_le := LE.of_neg + bot_le := + #adaptation_note + /-- + Added `by exact` after https://github.com/leanprover/lean4/pull/6053, + but don't understand why it was needed. + -/ + by exact LE.of_neg instance : HasDistribNeg SignType := { neg_neg := fun x => by cases x <;> rfl diff --git a/Mathlib/Data/String/Basic.lean b/Mathlib/Data/String/Basic.lean index d77a4e02a1f33..b4a8b44ddfbf8 100644 --- a/Mathlib/Data/String/Basic.lean +++ b/Mathlib/Data/String/Basic.lean @@ -31,7 +31,7 @@ def ltb (s₁ s₂ : Iterator) : Bool := instance LT' : LT String := ⟨fun s₁ s₂ ↦ ltb s₁.iter s₂.iter⟩ -instance decidableLT : @DecidableRel String (· < ·) := by +instance decidableLT : DecidableRel (α := String) (· < ·) := by simp only [LT'] infer_instance -- short-circuit type class inference @@ -100,7 +100,7 @@ theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList instance LE : LE String := ⟨fun s₁ s₂ ↦ ¬s₂ < s₁⟩ -instance decidableLE : @DecidableRel String (· ≤ ·) := by +instance decidableLE : DecidableRel (α := String) (· ≤ ·) := by simp only [LE] infer_instance -- short-circuit type class inference diff --git a/Mathlib/Data/Subtype.lean b/Mathlib/Data/Subtype.lean index e343f27f48c4b..79c2b5a26c935 100644 --- a/Mathlib/Data/Subtype.lean +++ b/Mathlib/Data/Subtype.lean @@ -33,7 +33,7 @@ attribute [coe] Subtype.val initialize_simps_projections Subtype (val → coe) /-- A version of `x.property` or `x.2` where `p` is syntactically applied to the coercion of `x` - instead of `x.1`. A similar result is `Subtype.mem` in `Data.Set.Basic`. -/ + instead of `x.1`. A similar result is `Subtype.mem` in `Mathlib.Data.Set.Basic`. -/ theorem prop (x : Subtype p) : p x := x.2 diff --git a/Mathlib/Data/Sym/Basic.lean b/Mathlib/Data/Sym/Basic.lean index ac156160cdcb8..4daed5e6c93fa 100644 --- a/Mathlib/Data/Sym/Basic.lean +++ b/Mathlib/Data/Sym/Basic.lean @@ -55,7 +55,7 @@ instance {α : Type*} {n : ℕ} [DecidableEq α] : DecidableEq (Sym α n) := See note [reducible non-instances]. -/ -abbrev Vector.Perm.isSetoid (α : Type*) (n : ℕ) : Setoid (Vector α n) := +abbrev Mathlib.Vector.Perm.isSetoid (α : Type*) (n : ℕ) : Setoid (Vector α n) := (List.isSetoid α).comap Subtype.val attribute [local instance] Vector.Perm.isSetoid @@ -119,20 +119,21 @@ theorem coe_cons (s : Sym α n) (a : α) : (a ::ₛ s : Multiset α) = a ::ₘ s /-- This is the quotient map that takes a list of n elements as an n-tuple and produces an nth symmetric power. -/ -def ofVector : Vector α n → Sym α n := +def ofVector : Mathlib.Vector α n → Sym α n := fun x => ⟨↑x.val, (Multiset.coe_card _).trans x.2⟩ /-- This is the quotient map that takes a list of n elements as an n-tuple and produces an nth symmetric power. -/ -instance : Coe (Vector α n) (Sym α n) where coe x := ofVector x +instance : Coe (Mathlib.Vector α n) (Sym α n) where coe x := ofVector x @[simp] -theorem ofVector_nil : ↑(Vector.nil : Vector α 0) = (Sym.nil : Sym α 0) := +theorem ofVector_nil : ↑(Vector.nil : Mathlib.Vector α 0) = (Sym.nil : Sym α 0) := rfl @[simp] -theorem ofVector_cons (a : α) (v : Vector α n) : ↑(Vector.cons a v) = a ::ₛ (↑v : Sym α n) := by +theorem ofVector_cons (a : α) (v : Mathlib.Vector α n) : + ↑(Vector.cons a v) = a ::ₛ (↑v : Sym α n) := by cases v rfl @@ -179,13 +180,13 @@ theorem mem_cons_of_mem (h : a ∈ s) : a ∈ b ::ₛ s := theorem mem_cons_self (a : α) (s : Sym α n) : a ∈ a ::ₛ s := Multiset.mem_cons_self a s.1 -theorem cons_of_coe_eq (a : α) (v : Vector α n) : a ::ₛ (↑v : Sym α n) = ↑(a ::ᵥ v) := +theorem cons_of_coe_eq (a : α) (v : Mathlib.Vector α n) : a ::ₛ (↑v : Sym α n) = ↑(a ::ᵥ v) := Subtype.ext <| by cases v rfl open scoped List in -theorem sound {a b : Vector α n} (h : a.val ~ b.val) : (↑a : Sym α n) = ↑b := +theorem sound {a b : Mathlib.Vector α n} (h : a.val ~ b.val) : (↑a : Sym α n) = ↑b := Subtype.ext <| Quotient.sound h /-- `erase s a h` is the sym that subtracts 1 from the @@ -384,7 +385,7 @@ def equivCongr (e : α ≃ β) : Sym α n ≃ Sym β n where /-- "Attach" a proof that `a ∈ s` to each element `a` in `s` to produce an element of the symmetric power on `{x // x ∈ s}`. -/ def attach (s : Sym α n) : Sym { x // x ∈ s } n := - ⟨s.val.attach, by (conv_rhs => rw [← s.2, ← Multiset.card_attach]); rfl⟩ + ⟨s.val.attach, by (conv_rhs => rw [← s.2, ← Multiset.card_attach])⟩ @[simp] theorem attach_mk {m : Multiset α} {hc : Multiset.card m = n} : @@ -440,7 +441,7 @@ theorem mem_cast (h : n = m) : a ∈ Sym.cast h s ↔ a ∈ s := /-- Append a pair of `Sym` terms. -/ def append (s : Sym α n) (s' : Sym α n') : Sym α (n + n') := - ⟨s.1 + s'.1, by rw [map_add, s.2, s'.2]⟩ + ⟨s.1 + s'.1, by rw [Multiset.card_add, s.2, s'.2]⟩ @[simp] theorem append_inj_right (s : Sym α n) {t t' : Sym α n'} : s.append t = s.append t' ↔ t = t' := diff --git a/Mathlib/Data/Sym/Sym2.lean b/Mathlib/Data/Sym/Sym2.lean index 28fbe8b4427a2..a827017219d56 100644 --- a/Mathlib/Data/Sym/Sym2.lean +++ b/Mathlib/Data/Sym/Sym2.lean @@ -586,7 +586,7 @@ section SymEquiv attribute [local instance] Vector.Perm.isSetoid -private def fromVector : Vector α 2 → α × α +private def fromVector : Mathlib.Vector α 2 → α × α | ⟨[a, b], _⟩ => (a, b) private theorem perm_card_two_iff {a₁ b₁ a₂ b₂ : α} : diff --git a/Mathlib/Data/Vector/Basic.lean b/Mathlib/Data/Vector/Basic.lean index 3739f74c8f540..f965bcd759bc9 100644 --- a/Mathlib/Data/Vector/Basic.lean +++ b/Mathlib/Data/Vector/Basic.lean @@ -7,7 +7,6 @@ import Mathlib.Algebra.BigOperators.Group.List import Mathlib.Data.Vector.Defs import Mathlib.Data.List.Nodup import Mathlib.Data.List.OfFn -import Mathlib.Data.List.InsertIdx import Mathlib.Control.Applicative import Mathlib.Control.Traversable.Basic @@ -527,8 +526,7 @@ variable {a : α} def insertIdx (a : α) (i : Fin (n + 1)) (v : Vector α n) : Vector α (n + 1) := ⟨v.1.insertIdx i a, by rw [List.length_insertIdx, v.2] - rw [v.2, ← Nat.succ_le_succ_iff] - exact i.2⟩ + split <;> omega⟩ @[deprecated (since := "2024-10-21")] alias insertNth := insertIdx diff --git a/Mathlib/Data/Vector/Mem.lean b/Mathlib/Data/Vector/Mem.lean index 3eb0fe6678d82..dc09c5bb58415 100644 --- a/Mathlib/Data/Vector/Mem.lean +++ b/Mathlib/Data/Vector/Mem.lean @@ -22,9 +22,7 @@ namespace Vector variable {α β : Type*} {n : ℕ} (a a' : α) @[simp] -theorem get_mem (i : Fin n) (v : Vector α n) : v.get i ∈ v.toList := by - rw [get_eq_get] - exact List.get_mem _ _ _ +theorem get_mem (i : Fin n) (v : Vector α n) : v.get i ∈ v.toList := List.get_mem _ _ theorem mem_iff_get (v : Vector α n) : a ∈ v.toList ↔ ∃ i, v.get i = a := by simp only [List.mem_iff_get, Fin.exists_iff, Vector.get_eq_get] diff --git a/Mathlib/Data/ZMod/Basic.lean b/Mathlib/Data/ZMod/Basic.lean index 43e41f0704f39..37dffbc1303eb 100644 --- a/Mathlib/Data/ZMod/Basic.lean +++ b/Mathlib/Data/ZMod/Basic.lean @@ -1575,6 +1575,6 @@ def Nat.residueClassesEquiv (N : ℕ) [NeZero N] : ℕ ≃ ZMod N × ℕ where · simp only [add_comm p.1.val, cast_add, cast_mul, natCast_self, zero_mul, natCast_val, cast_id', id_eq, zero_add] · simp only [add_comm p.1.val, mul_add_div (NeZero.pos _), - (Nat.div_eq_zero_iff <| (NeZero.pos _)).2 p.1.val_lt, add_zero] + (Nat.div_eq_zero_iff).2 <| .inr p.1.val_lt, add_zero] set_option linter.style.longFile 1700 diff --git a/Mathlib/Deprecated/Cardinal/Continuum.lean b/Mathlib/Deprecated/Cardinal/Continuum.lean new file mode 100644 index 0000000000000..42c2d813ef442 --- /dev/null +++ b/Mathlib/Deprecated/Cardinal/Continuum.lean @@ -0,0 +1,25 @@ +/- +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, Floris van Doorn, Violeta Hernández Palacios +-/ +import Mathlib.SetTheory.Cardinal.Continuum +import Mathlib.Deprecated.Cardinal.PartENat + +/-! +# Deprecated material from Mathlib.SetTheory.Cardinal.Aleph and Mathlib.SetTheory.Cardinal.Continuum + +Moved here so we can reduce imports sooner. +-/ + +namespace Cardinal + +@[simp, deprecated aleph_toENat (since := "2024-12-01")] +theorem aleph_toPartENat (o : Ordinal) : toPartENat (ℵ_ o) = ⊤ := + toPartENat_apply_of_aleph0_le <| aleph0_le_aleph o + +@[simp, deprecated aleph_toENat (since := "2024-12-01")] +theorem continuum_toPartENat : toPartENat continuum = ⊤ := + toPartENat_apply_of_aleph0_le aleph0_le_continuum + +end Cardinal diff --git a/Mathlib/Deprecated/Cardinal/Finite.lean b/Mathlib/Deprecated/Cardinal/Finite.lean new file mode 100644 index 0000000000000..f28497050cfda --- /dev/null +++ b/Mathlib/Deprecated/Cardinal/Finite.lean @@ -0,0 +1,121 @@ +/- +Copyright (c) 2021 Aaron Anderson. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Aaron Anderson +-/ +import Mathlib.Deprecated.Cardinal.PartENat +import Mathlib.SetTheory.Cardinal.Finite +import Mathlib.Data.Finite.Card + +/-! +# Deprecated material on `PartENat.card`. +-/ + +noncomputable section + +universe u v +variable {α : Type u} + +open Cardinal + +namespace PartENat + +/-- `PartENat.card α` is the cardinality of `α` as an extended natural number. + If `α` is infinite, `PartENat.card α = ⊤`. -/ +@[deprecated ENat.card (since := "2024-12-01")] +def card (α : Type*) : PartENat := + toPartENat (mk α) + +-- This rest of this file is about the deprecated `PartENat.card`. +set_option linter.deprecated false + +@[simp] +theorem card_eq_coe_fintype_card [Fintype α] : card α = Fintype.card α := + mk_toPartENat_eq_coe_card + +@[simp] +theorem card_eq_top_of_infinite [Infinite α] : card α = ⊤ := + mk_toPartENat_of_infinite + +@[simp] +theorem card_sum (α β : Type*) : + PartENat.card (α ⊕ β) = PartENat.card α + PartENat.card β := by + simp only [PartENat.card, Cardinal.mk_sum, map_add, Cardinal.toPartENat_lift] + +theorem card_congr {α : Type*} {β : Type*} (f : α ≃ β) : PartENat.card α = PartENat.card β := + Cardinal.toPartENat_congr f + +@[simp] lemma card_ulift (α : Type*) : card (ULift α) = card α := card_congr Equiv.ulift + +@[simp] lemma card_plift (α : Type*) : card (PLift α) = card α := card_congr Equiv.plift + +theorem card_image_of_injOn {α : Type u} {β : Type v} {f : α → β} {s : Set α} (h : Set.InjOn f s) : + card (f '' s) = card s := + card_congr (Equiv.Set.imageOfInjOn f s h).symm + +theorem card_image_of_injective {α : Type u} {β : Type v} (f : α → β) (s : Set α) + (h : Function.Injective f) : card (f '' s) = card s := card_image_of_injOn h.injOn + +-- Should I keep the 6 following lemmas ? +-- TODO: Add ofNat, zero, and one versions for simp confluence +@[simp] +theorem _root_.Cardinal.natCast_le_toPartENat_iff {n : ℕ} {c : Cardinal} : + ↑n ≤ toPartENat c ↔ ↑n ≤ c := by + rw [← toPartENat_natCast n, toPartENat_le_iff_of_le_aleph0 (le_of_lt (nat_lt_aleph0 n))] + +@[simp] +theorem _root_.Cardinal.toPartENat_le_natCast_iff {c : Cardinal} {n : ℕ} : + toPartENat c ≤ n ↔ c ≤ n := by + rw [← toPartENat_natCast n, toPartENat_le_iff_of_lt_aleph0 (nat_lt_aleph0 n)] + +@[simp] +theorem _root_.Cardinal.natCast_eq_toPartENat_iff {n : ℕ} {c : Cardinal} : + ↑n = toPartENat c ↔ ↑n = c := by + rw [le_antisymm_iff, le_antisymm_iff, Cardinal.toPartENat_le_natCast_iff, + Cardinal.natCast_le_toPartENat_iff] + +@[simp] +theorem _root_.Cardinal.toPartENat_eq_natCast_iff {c : Cardinal} {n : ℕ} : + Cardinal.toPartENat c = n ↔ c = n := by +rw [eq_comm, Cardinal.natCast_eq_toPartENat_iff, eq_comm] + +@[simp] +theorem _root_.Cardinal.natCast_lt_toPartENat_iff {n : ℕ} {c : Cardinal} : + ↑n < toPartENat c ↔ ↑n < c := by + simp only [← not_le, Cardinal.toPartENat_le_natCast_iff] + +@[simp] +theorem _root_.Cardinal.toPartENat_lt_natCast_iff {n : ℕ} {c : Cardinal} : + toPartENat c < ↑n ↔ c < ↑n := by + simp only [← not_le, Cardinal.natCast_le_toPartENat_iff] + +theorem card_eq_zero_iff_empty (α : Type*) : card α = 0 ↔ IsEmpty α := by + rw [← Cardinal.mk_eq_zero_iff] + conv_rhs => rw [← Nat.cast_zero] + simp only [← Cardinal.toPartENat_eq_natCast_iff] + simp only [PartENat.card, Nat.cast_zero] + +theorem card_le_one_iff_subsingleton (α : Type*) : card α ≤ 1 ↔ Subsingleton α := by + rw [← le_one_iff_subsingleton] + conv_rhs => rw [← Nat.cast_one] + rw [← Cardinal.toPartENat_le_natCast_iff] + simp only [PartENat.card, Nat.cast_one] + +theorem one_lt_card_iff_nontrivial (α : Type*) : 1 < card α ↔ Nontrivial α := by + rw [← Cardinal.one_lt_iff_nontrivial] + conv_rhs => rw [← Nat.cast_one] + rw [← natCast_lt_toPartENat_iff] + simp only [PartENat.card, Nat.cast_one] + +set_option linter.deprecated false in +@[deprecated ENat.card_eq_coe_natCard (since := "2024-11-30")] +theorem card_eq_coe_natCard (α : Type*) [Finite α] : card α = Nat.card α := by + unfold PartENat.card + apply symm + rw [Cardinal.natCast_eq_toPartENat_iff] + exact Finite.cast_card_eq_mk + + +@[deprecated (since := "2024-05-25")] alias card_eq_coe_nat_card := card_eq_coe_natCard + +end PartENat diff --git a/Mathlib/SetTheory/Cardinal/PartENat.lean b/Mathlib/Deprecated/Cardinal/PartENat.lean similarity index 100% rename from Mathlib/SetTheory/Cardinal/PartENat.lean rename to Mathlib/Deprecated/Cardinal/PartENat.lean diff --git a/Mathlib/Deprecated/Order.lean b/Mathlib/Deprecated/Order.lean index 9f79797c7e46f..65fab91526170 100644 --- a/Mathlib/Deprecated/Order.lean +++ b/Mathlib/Deprecated/Order.lean @@ -12,7 +12,7 @@ import Mathlib.Order.Defs.LinearOrder variable {α : Type*} -@[deprecated (since := "2024-11-26")] -- unused in Mathlib +@[deprecated "This was a leftover from Lean 3, and has not been needed." (since := "2024-11-26")] instance isStrictTotalOrder_of_linearOrder [LinearOrder α] : IsStrictTotalOrder α (· < ·) where irrefl := lt_irrefl trichotomous := lt_trichotomy diff --git a/Mathlib/Deprecated/Subfield.lean b/Mathlib/Deprecated/Subfield.lean index f1d508d21d08d..3ce93a3a26acc 100644 --- a/Mathlib/Deprecated/Subfield.lean +++ b/Mathlib/Deprecated/Subfield.lean @@ -125,6 +125,7 @@ theorem closure_subset {T : Set F} (hT : IsSubfield T) (H : S ⊆ T) : closure S theorem closure_subset_iff {s t : Set F} (ht : IsSubfield t) : closure s ⊆ t ↔ s ⊆ t := ⟨Set.Subset.trans subset_closure, closure_subset ht⟩ +@[gcongr] theorem closure_mono {s t : Set F} (H : s ⊆ t) : closure s ⊆ closure t := closure_subset closure.isSubfield <| Set.Subset.trans H subset_closure diff --git a/Mathlib/Deprecated/Subgroup.lean b/Mathlib/Deprecated/Subgroup.lean index 64fd450477d80..3842d160c48ac 100644 --- a/Mathlib/Deprecated/Subgroup.lean +++ b/Mathlib/Deprecated/Subgroup.lean @@ -442,7 +442,7 @@ theorem closure_subset {s t : Set G} (ht : IsSubgroup t) (h : s ⊆ t) : closure theorem closure_subset_iff {s t : Set G} (ht : IsSubgroup t) : closure s ⊆ t ↔ s ⊆ t := ⟨fun h _ ha => h (mem_closure ha), fun h _ ha => closure_subset ht h ha⟩ -@[to_additive] +@[to_additive (attr := gcongr)] theorem closure_mono {s t : Set G} (h : s ⊆ t) : closure s ⊆ closure t := closure_subset (closure.isSubgroup _) <| Set.Subset.trans h subset_closure @@ -600,6 +600,7 @@ theorem normalClosure_subset_iff {s t : Set G} (ht : IsNormalSubgroup t) : s ⊆ t ↔ normalClosure s ⊆ t := ⟨normalClosure_subset ht, Set.Subset.trans subset_normalClosure⟩ +@[gcongr] theorem normalClosure_mono {s t : Set G} : s ⊆ t → normalClosure s ⊆ normalClosure t := fun h => normalClosure_subset normalClosure.is_normal (Set.Subset.trans h subset_normalClosure) diff --git a/Mathlib/Deprecated/Submonoid.lean b/Mathlib/Deprecated/Submonoid.lean index 639dc73b90592..2e9618d300fb9 100644 --- a/Mathlib/Deprecated/Submonoid.lean +++ b/Mathlib/Deprecated/Submonoid.lean @@ -268,7 +268,7 @@ theorem closure_subset {s t : Set M} (ht : IsSubmonoid t) (h : s ⊆ t) : Closur /-- Given subsets `t` and `s` of a monoid `M`, if `s ⊆ t`, the submonoid of `M` generated by `s` is contained in the submonoid generated by `t`. -/ -@[to_additive +@[to_additive (attr := gcongr) "Given subsets `t` and `s` of an `AddMonoid M`, if `s ⊆ t`, the `AddSubmonoid` of `M` generated by `s` is contained in the `AddSubmonoid` generated by `t`."] theorem closure_mono {s t : Set M} (h : s ⊆ t) : Closure s ⊆ Closure t := diff --git a/Mathlib/Deprecated/Subring.lean b/Mathlib/Deprecated/Subring.lean index a26eec3948fb8..05bea1fc07bb0 100644 --- a/Mathlib/Deprecated/Subring.lean +++ b/Mathlib/Deprecated/Subring.lean @@ -179,6 +179,7 @@ theorem closure_subset_iff {s t : Set R} (ht : IsSubring t) : closure s ⊆ t (AddGroup.closure_subset_iff ht.toIsAddSubgroup).trans ⟨Set.Subset.trans Monoid.subset_closure, Monoid.closure_subset ht.toIsSubmonoid⟩ +@[gcongr] theorem closure_mono {s t : Set R} (H : s ⊆ t) : closure s ⊆ closure t := closure_subset closure.isSubring <| Set.Subset.trans H subset_closure diff --git a/Mathlib/Dynamics/Newton.lean b/Mathlib/Dynamics/Newton.lean index 94030f064065f..3a68a8bf036e7 100644 --- a/Mathlib/Dynamics/Newton.lean +++ b/Mathlib/Dynamics/Newton.lean @@ -111,7 +111,7 @@ theorem exists_unique_nilpotent_sub_and_aeval_eq_zero · -- Existence obtain ⟨n, hn⟩ := id h refine ⟨P.newtonMap^[n] x, isNilpotent_iterate_newtonMap_sub_of_isNilpotent h n, ?_⟩ - rw [← zero_dvd_iff, ← pow_eq_zero_of_le n.lt_two_pow.le hn] + rw [← zero_dvd_iff, ← pow_eq_zero_of_le (n.lt_two_pow_self).le hn] exact aeval_pow_two_pow_dvd_aeval_iterate_newtonMap h h' n · -- Uniqueness have ⟨u, hu⟩ := binomExpansion (P.map (algebraMap R S)) r₁ (r₂ - r₁) diff --git a/Mathlib/Dynamics/OmegaLimit.lean b/Mathlib/Dynamics/OmegaLimit.lean index 7de977bddf6ba..d2ba2df728a80 100644 --- a/Mathlib/Dynamics/OmegaLimit.lean +++ b/Mathlib/Dynamics/OmegaLimit.lean @@ -84,7 +84,7 @@ theorem mapsTo_omegaLimit' {α' β' : Type*} [TopologicalSpace β'] {f : Filter MapsTo gb (ω f ϕ s) (ω f ϕ' s') := by simp only [omegaLimit_def, mem_iInter, MapsTo] intro y hy u hu - refine map_mem_closure hgc (hy _ (inter_mem hu hg)) (forall_image2_iff.2 fun t ht x hx ↦ ?_) + refine map_mem_closure hgc (hy _ (inter_mem hu hg)) (forall_mem_image2.2 fun t ht x hx ↦ ?_) calc ϕ' t (ga x) ∈ image2 ϕ' u s' := mem_image2_of_mem ht.1 (hs hx) _ = gb (ϕ t x) := ht.2 hx |>.symm diff --git a/Mathlib/FieldTheory/Adjoin.lean b/Mathlib/FieldTheory/Adjoin.lean index 51d8f9c940bb7..54c839c356865 100644 --- a/Mathlib/FieldTheory/Adjoin.lean +++ b/Mathlib/FieldTheory/Adjoin.lean @@ -12,6 +12,7 @@ import Mathlib.RingTheory.Adjoin.Dimension import Mathlib.RingTheory.Finiteness.TensorProduct import Mathlib.RingTheory.TensorProduct.Basic import Mathlib.SetTheory.Cardinal.Subfield +import Mathlib.LinearAlgebra.Dual /-! # Adjoining Elements to Fields diff --git a/Mathlib/FieldTheory/AlgebraicClosure.lean b/Mathlib/FieldTheory/AlgebraicClosure.lean index 8307314cbe26b..056881d31cde2 100644 --- a/Mathlib/FieldTheory/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/AlgebraicClosure.lean @@ -38,6 +38,9 @@ def algebraicClosure : IntermediateField F E := variable {F E} +theorem algebraicClosure_toSubalgebra : + (algebraicClosure F E).toSubalgebra = integralClosure F E := rfl + /-- An element is contained in the algebraic closure of `F` in `E` if and only if it is an integral element. -/ theorem mem_algebraicClosure_iff' {x : E} : @@ -94,14 +97,13 @@ def algEquivOfAlgEquiv (i : E ≃ₐ[F] K) : algebraicClosure F E ≃ₐ[F] algebraicClosure F K := (intermediateFieldMap i _).trans (equivOfEq (map_eq_of_algEquiv i)) -alias AlgEquiv.algebraicClosure := algebraicClosure.algEquivOfAlgEquiv +alias _root_.AlgEquiv.algebraicClosure := algEquivOfAlgEquiv variable (F E K) /-- The algebraic closure of `F` in `E` is algebraic over `F`. -/ instance isAlgebraic : Algebra.IsAlgebraic F (algebraicClosure F E) := - ⟨fun x ↦ - isAlgebraic_iff.mpr (IsAlgebraic.isIntegral (mem_algebraicClosure_iff.mp x.2)).isAlgebraic⟩ + ⟨fun x ↦ isAlgebraic_iff.mpr x.2.isAlgebraic⟩ /-- The algebraic closure of `F` in `E` is the integral closure of `F` in `E`. -/ instance isIntegralClosure : IsIntegralClosure (algebraicClosure F E) F E := @@ -109,6 +111,10 @@ instance isIntegralClosure : IsIntegralClosure (algebraicClosure F E) F E := end algebraicClosure +protected theorem Transcendental.algebraicClosure {a : E} (ha : Transcendental F a) : + Transcendental (algebraicClosure F E) a := + ha.extendScalars Subtype.val_injective + variable (F E K) /-- An intermediate field of `E / F` is contained in the algebraic closure of `F` in `E` diff --git a/Mathlib/FieldTheory/AxGrothendieck.lean b/Mathlib/FieldTheory/AxGrothendieck.lean index b3ce93355bef9..a7bc963365950 100644 --- a/Mathlib/FieldTheory/AxGrothendieck.lean +++ b/Mathlib/FieldTheory/AxGrothendieck.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Basic import Mathlib.Data.Fintype.Card import Mathlib.ModelTheory.Algebra.Field.IsAlgClosed import Mathlib.ModelTheory.Algebra.Ring.Definability @@ -160,7 +160,11 @@ theorem realize_genericPolyMapSurjOnOfInjOn Set.MapsTo, Set.mem_def, injOnAlt, funext_iff, Set.SurjOn, Set.image, setOf, Set.subset_def, Equiv.forall_congr_left (mvPolynomialSupportLEEquiv mons)] simp +singlePass only [← Sum.elim_comp_inl_inr] - simp [Set.mem_def, Function.comp_def] + -- was `simp` and very slow (https://github.com/leanprover-community/mathlib4/issues/19751) + simp only [Function.comp_def, Sum.elim_inl, Sum.elim_inr, Fin.castAdd_zero, Fin.cast_eq_self, + Nat.add_zero, Term.realize_var, Term.realize_relabel, realize_termOfFreeCommRing, + lift_genericPolyMap, Nat.reduceAdd, Fin.isValue, Function.uncurry_apply_pair, Fin.cons_zero, + Fin.cons_one, ↓reduceIte, one_ne_zero] theorem ACF_models_genericPolyMapSurjOnOfInjOn_of_prime [Fintype ι] {p : ℕ} (hp : p.Prime) (φ : ring.Formula (α ⊕ ι)) (mons : ι → Finset (ι →₀ ℕ)) : diff --git a/Mathlib/FieldTheory/Extension.lean b/Mathlib/FieldTheory/Extension.lean index 142e5ed48085b..131f0f917c5ff 100644 --- a/Mathlib/FieldTheory/Extension.lean +++ b/Mathlib/FieldTheory/Extension.lean @@ -183,7 +183,7 @@ theorem nonempty_algHom_of_exist_lifts_finset [alg : Algebra.IsAlgebraic F E] have := finiteDimensional_adjoin (S := {α}) fun _ _ ↦ ((alg.tower_top ϕ.carrier).isIntegral).1 _ let L (σ : Λ) : Lifts F E K := ⟨ϕ.carrier⟮α⟯.restrictScalars F, σ.restrictScalars F⟩ have hL (σ : Λ) : ϕ < L σ := lt_iff.mpr - ⟨by simpa only [restrictScalars_adjoin_eq_sup, left_lt_sup, adjoin_simple_le_iff], + ⟨by simpa only [L, restrictScalars_adjoin_eq_sup, left_lt_sup, adjoin_simple_le_iff], AlgHom.coe_ringHom_injective σ.comp_algebraMap⟩ have ⟨(ϕ_ext : ϕ.IsExtendible), ϕ_max⟩ := maximal_iff_forall_gt.mp hϕ simp_rw [Set.mem_setOf, IsExtendible] at ϕ_max; push_neg at ϕ_max diff --git a/Mathlib/FieldTheory/Finite/Polynomial.lean b/Mathlib/FieldTheory/Finite/Polynomial.lean index fa34749883456..d93f2b2225060 100644 --- a/Mathlib/FieldTheory/Finite/Polynomial.lean +++ b/Mathlib/FieldTheory/Finite/Polynomial.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.MvPolynomial.Expand import Mathlib.FieldTheory.Finite.Basic import Mathlib.LinearAlgebra.FiniteDimensional import Mathlib.RingTheory.MvPolynomial.Basic +import Mathlib.LinearAlgebra.Dual /-! ## Polynomials over finite fields diff --git a/Mathlib/FieldTheory/Galois/Basic.lean b/Mathlib/FieldTheory/Galois/Basic.lean index 22fbc7307b2ad..86c87ea00d274 100644 --- a/Mathlib/FieldTheory/Galois/Basic.lean +++ b/Mathlib/FieldTheory/Galois/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2020 Thomas Browning, Patrick Lutz. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Thomas Browning, Patrick Lutz +Authors: Thomas Browning, Patrick Lutz, Yongle Hu, Jingting Wang -/ import Mathlib.FieldTheory.Fixed import Mathlib.FieldTheory.NormalClosure @@ -289,6 +289,72 @@ def galoisCoinsertionIntermediateFieldSubgroup [FiniteDimensional F E] [IsGalois end IsGalois +section + +/-In this section we prove that the normal subgroups correspond to the Galois subextensions +in the Galois correspondence and its related results.-/ + +variable {K L : Type*} [Field K] [Field L] [Algebra K L] + +open IntermediateField + +open scoped Pointwise + +lemma IntermediateField.restrictNormalHom_ker (E : IntermediateField K L) [Normal K E] : + (restrictNormalHom E).ker = E.fixingSubgroup := by + simp [fixingSubgroup, Subgroup.ext_iff, AlgEquiv.ext_iff, Subtype.ext_iff, + restrictNormalHom_apply, mem_fixingSubgroup_iff] + +namespace IsGalois + +variable (E : IntermediateField K L) + +/-- If `H` is a normal Subgroup of `Gal(L / K)`, then `fixedField H` is Galois over `K`. -/ +instance of_fixedField_normal_subgroup [IsGalois K L] + (H : Subgroup (L ≃ₐ[K] L)) [hn : Subgroup.Normal H] : IsGalois K (fixedField H) where + to_isSeparable := Algebra.isSeparable_tower_bot_of_isSeparable K (fixedField H) L + to_normal := by + apply normal_iff_forall_map_le'.mpr + rintro σ x ⟨a, ha, rfl⟩ τ + exact (symm_apply_eq σ).mp (ha ⟨σ⁻¹ * τ * σ, Subgroup.Normal.conj_mem' hn τ.1 τ.2 σ⟩) + +/-- If `H` is a normal Subgroup of `Gal(L / K)`, then `Gal(fixedField H / K)` is isomorphic to +`Gal(L / K) ⧸ H`. -/ +noncomputable def normalAutEquivQuotient [FiniteDimensional K L] [IsGalois K L] + (H : Subgroup (L ≃ₐ[K] L)) [Subgroup.Normal H] : + (L ≃ₐ[K] L) ⧸ H ≃* ((fixedField H) ≃ₐ[K] (fixedField H)) := + (QuotientGroup.quotientMulEquivOfEq ((fixingSubgroup_fixedField H).symm.trans + (fixedField H).restrictNormalHom_ker.symm)).trans <| + QuotientGroup.quotientKerEquivOfSurjective (restrictNormalHom (fixedField H)) <| + restrictNormalHom_surjective L + +lemma normalAutEquivQuotient_apply [FiniteDimensional K L] [IsGalois K L] + (H : Subgroup (L ≃ₐ[K] L)) [Subgroup.Normal H] (σ : (L ≃ₐ[K] L)) : + normalAutEquivQuotient H σ = (restrictNormalHom (fixedField H)) σ := rfl + +open scoped Pointwise + +@[simp] +theorem map_fixingSubgroup (σ : L ≃ₐ[K] L) : + (E.map σ).fixingSubgroup = (MulAut.conj σ) • E.fixingSubgroup := by + ext τ + simp only [coe_map, AlgHom.coe_coe, Set.mem_image, SetLike.mem_coe, AlgEquiv.smul_def, + forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, Subtype.forall, + Subgroup.mem_pointwise_smul_iff_inv_smul_mem, ← symm_apply_eq, + IntermediateField.fixingSubgroup, mem_fixingSubgroup_iff] + rfl + +/-- Let `E` be an intermediateField of a Galois extension `L / K`. If `E / K` is +Galois extension, then `E.fixingSubgroup` is a normal subgroup of `Gal(L / K)`. -/ +instance fixingSubgroup_normal_of_isGalois [IsGalois K L] [IsGalois K E] : + E.fixingSubgroup.Normal := by + apply Subgroup.Normal.of_conjugate_fixed (fun σ ↦ ?_) + rw [← map_fixingSubgroup, normal_iff_forall_map_eq'.mp inferInstance σ] + +end IsGalois + +end + end GaloisCorrespondence section GaloisEquivalentDefinitions diff --git a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean index fadc8889330f0..db5ed7f190e80 100644 --- a/Mathlib/FieldTheory/IntermediateField/Algebraic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Algebraic.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Anne Baanen -/ import Mathlib.FieldTheory.IntermediateField.Basic -import Mathlib.RingTheory.Algebraic -import Mathlib.FieldTheory.Tower import Mathlib.FieldTheory.Minpoly.Basic +import Mathlib.FieldTheory.Tower import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition +import Mathlib.RingTheory.Algebraic.Integral /-! # Results on finite dimensionality and algebraicity of intermediate fields. diff --git a/Mathlib/FieldTheory/IntermediateField/Basic.lean b/Mathlib/FieldTheory/IntermediateField/Basic.lean index 33d4aa8b3bf97..0e047a0ddb3f5 100644 --- a/Mathlib/FieldTheory/IntermediateField/Basic.lean +++ b/Mathlib/FieldTheory/IntermediateField/Basic.lean @@ -3,6 +3,7 @@ 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.Algebra.Algebra.Subalgebra.Tower import Mathlib.Algebra.Field.IsField import Mathlib.Algebra.Field.Subfield.Basic import Mathlib.Algebra.Polynomial.AlgebraMap @@ -613,6 +614,19 @@ theorem mem_lift {F : IntermediateField K L} {E : IntermediateField K F} (x : F) x.1 ∈ lift E ↔ x ∈ E := Subtype.val_injective.mem_set_image +/--The algEquiv between an intermediate field and its lift-/ +def liftAlgEquiv {E : IntermediateField K L} (F : IntermediateField K E) : ↥F ≃ₐ[K] lift F where + toFun x := ⟨x.1.1, (mem_lift x.1).mpr x.2⟩ + invFun x := ⟨⟨x.1, lift_le F x.2⟩, (mem_lift ⟨x.1, lift_le F x.2⟩).mp x.2⟩ + left_inv := congrFun rfl + right_inv := congrFun rfl + map_mul' _ _ := rfl + map_add' _ _ := rfl + commutes' _ := rfl + +lemma liftAlgEquiv_apply {E : IntermediateField K L} (F : IntermediateField K E) (x : F) : + (liftAlgEquiv F x).1 = x := rfl + section RestrictScalars variable (K) diff --git a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean index d91f6a62d0512..2c5ad01a7762a 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/AlgebraicClosure.lean @@ -3,10 +3,8 @@ Copyright (c) 2020 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ -import Mathlib.Algebra.DirectLimit import Mathlib.Algebra.CharP.Algebra -import Mathlib.Algebra.Polynomial.Eval.Irreducible -import Mathlib.FieldTheory.IsAlgClosed.Basic +import Mathlib.FieldTheory.Isaacs import Mathlib.FieldTheory.SplittingField.Construction /-! @@ -19,8 +17,9 @@ In this file we construct the algebraic closure of a field - `AlgebraicClosure k` is an algebraic closure of `k` (in the same universe). It is constructed by taking the polynomial ring generated by indeterminates `x_f` corresponding to monic irreducible polynomials `f` with coefficients in `k`, and quotienting - out by a maximal ideal containing every `f(x_f)`, and then repeating this step countably - many times. See Exercise 1.13 in Atiyah--Macdonald. + out by a maximal ideal containing every `f(x_f)`. Usually this needs to be repeated countably + many times (see Exercise 1.13 in [atiyah-macdonald]), but using a theorem of Isaacs [Isaacs1980], + once is enough (see https://kconrad.math.uconn.edu/blurbs/galoistheory/algclosure.pdf). ## Tags @@ -93,255 +92,14 @@ instance maxIdeal.isMaximal : (maxIdeal k).IsMaximal := theorem le_maxIdeal : spanEval k ≤ maxIdeal k := (Classical.choose_spec <| Ideal.exists_le_maximal _ <| spanEval_ne_top k).2 -/-- The first step of constructing `AlgebraicClosure`: adjoin a root of all monic polynomials -/ -def AdjoinMonic : Type u := - MvPolynomial (MonicIrreducible k) k ⧸ maxIdeal k - -instance AdjoinMonic.field : Field (AdjoinMonic k) := - Ideal.Quotient.field _ - -instance AdjoinMonic.inhabited : Inhabited (AdjoinMonic k) := - ⟨37⟩ - -/-- The canonical ring homomorphism to `AdjoinMonic k`. -/ -def toAdjoinMonic : k →+* AdjoinMonic k := - (Ideal.Quotient.mk _).comp C - -instance AdjoinMonic.algebra : Algebra k (AdjoinMonic k) := - (toAdjoinMonic k).toAlgebra - --- Porting note: In the statement, the type of `C` had to be made explicit. -theorem AdjoinMonic.algebraMap : algebraMap k (AdjoinMonic k) = (Ideal.Quotient.mk _).comp - (C : k →+* MvPolynomial (MonicIrreducible k) k) := rfl - -theorem AdjoinMonic.isIntegral (z : AdjoinMonic k) : IsIntegral k z := by - let ⟨p, hp⟩ := Ideal.Quotient.mk_surjective z - rw [← hp] - induction p using MvPolynomial.induction_on generalizing z with - | h_C => exact isIntegral_algebraMap - | h_add _ _ ha hb => exact (ha _ rfl).add (hb _ rfl) - | h_X p f ih => - refine @IsIntegral.mul k _ _ _ _ _ (Ideal.Quotient.mk (maxIdeal k) _) (ih _ rfl) ?_ - refine ⟨f, f.2.1, ?_⟩ - erw [AdjoinMonic.algebraMap, ← hom_eval₂, Ideal.Quotient.eq_zero_iff_mem] - exact le_maxIdeal k (Ideal.subset_span ⟨f, rfl⟩) - -theorem AdjoinMonic.exists_root {f : k[X]} (hfm : f.Monic) (hfi : Irreducible f) : - ∃ x : AdjoinMonic k, f.eval₂ (toAdjoinMonic k) x = 0 := - ⟨Ideal.Quotient.mk _ <| X (⟨f, hfm, hfi⟩ : MonicIrreducible k), by - -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [toAdjoinMonic, ← hom_eval₂, Ideal.Quotient.eq_zero_iff_mem] - exact le_maxIdeal k (Ideal.subset_span <| ⟨_, rfl⟩)⟩ - -/-- The `n`th step of constructing `AlgebraicClosure`, together with its `Field` instance. -/ -def stepAux (n : ℕ) : Σ α : Type u, Field α := - Nat.recOn n ⟨k, inferInstance⟩ fun _ ih => ⟨@AdjoinMonic ih.1 ih.2, @AdjoinMonic.field ih.1 ih.2⟩ - -/-- The `n`th step of constructing `AlgebraicClosure`. -/ -def Step (n : ℕ) : Type u := - (stepAux k n).1 - --- Porting note: added during the port to help in the proof of `Step.isIntegral` below. -theorem Step.zero : Step k 0 = k := rfl - -instance Step.field (n : ℕ) : Field (Step k n) := - (stepAux k n).2 - --- Porting note: added during the port to help in the proof of `Step.isIntegral` below. -theorem Step.succ (n : ℕ) : Step k (n + 1) = AdjoinMonic (Step k n) := rfl - -instance Step.inhabited (n) : Inhabited (Step k n) := - ⟨37⟩ - -/-- The canonical inclusion to the `0`th step. -/ -def toStepZero : k →+* Step k 0 := - RingHom.id k - -/-- The canonical ring homomorphism to the next step. -/ -def toStepSucc (n : ℕ) : Step k n →+* (Step k (n + 1)) := - @toAdjoinMonic (Step k n) (Step.field k n) - -instance Step.algebraSucc (n) : Algebra (Step k n) (Step k (n + 1)) := - (toStepSucc k n).toAlgebra - -theorem toStepSucc.exists_root {n} {f : Polynomial (Step k n)} (hfm : f.Monic) - (hfi : Irreducible f) : ∃ x : Step k (n + 1), f.eval₂ (toStepSucc k n) x = 0 := - @AdjoinMonic.exists_root _ (Step.field k n) _ hfm hfi - --- Porting note: the following two declarations were added during the port to be used in the --- definition of toStepOfLE -private def toStepOfLE' (m n : ℕ) (h : m ≤ n) : Step k m → Step k n := -Nat.leRecOn h @fun a => toStepSucc k a - -private theorem toStepOfLE'.succ (m n : ℕ) (h : m ≤ n) : - toStepOfLE' k m (Nat.succ n) (h.trans n.le_succ) = - (toStepSucc k n) ∘ toStepOfLE' k m n h := by - ext x - exact Nat.leRecOn_succ h x - -/-- The canonical ring homomorphism to a step with a greater index. -/ -def toStepOfLE (m n : ℕ) (h : m ≤ n) : Step k m →+* Step k n where - toFun := toStepOfLE' k m n h - map_one' := by - induction' h with a h ih - · exact Nat.leRecOn_self 1 - · simp [toStepOfLE'.succ k m a h, ih] - map_mul' x y := by - simp only - induction' h with a h ih - · simp_rw [toStepOfLE', Nat.leRecOn_self] - · simp [toStepOfLE'.succ k m a h, ih] - map_zero' := by - simp only - induction' h with a h ih - · exact Nat.leRecOn_self 0 - · simp [toStepOfLE'.succ k m a h, ih] - map_add' x y := by - simp only - induction' h with a h ih - · simp_rw [toStepOfLE', Nat.leRecOn_self] - · simp [toStepOfLE'.succ k m a h, ih] - -@[simp] -theorem coe_toStepOfLE (m n : ℕ) (h : m ≤ n) : - (toStepOfLE k m n h : Step k m → Step k n) = Nat.leRecOn h @fun n => toStepSucc k n := - rfl - -instance Step.algebra (n) : Algebra k (Step k n) := - (toStepOfLE k 0 n n.zero_le).toAlgebra - -instance Step.scalar_tower (n) : IsScalarTower k (Step k n) (Step k (n + 1)) := - IsScalarTower.of_algebraMap_eq fun z => - @Nat.leRecOn_succ (Step k) 0 n n.zero_le (n + 1).zero_le (@fun n => toStepSucc k n) z - --- Porting note: Added to make `Step.isIntegral` faster -private theorem toStepOfLE.succ (n : ℕ) (h : 0 ≤ n) : - toStepOfLE k 0 (n + 1) (h.trans n.le_succ) = - (toStepSucc k n).comp (toStepOfLE k 0 n h) := by - ext1 x - rw [RingHom.comp_apply] - simp only [toStepOfLE, RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk] - change _ = (_ ∘ _) x - rw [toStepOfLE'.succ k 0 n h] - -theorem Step.isIntegral (n) : ∀ z : Step k n, IsIntegral k z := by - induction' n with a h - · intro z - exact isIntegral_algebraMap - · intro z - change RingHom.IsIntegralElem _ _ - revert z - change RingHom.IsIntegral _ - unfold algebraMap - unfold Algebra.toRingHom - unfold algebra - unfold RingHom.toAlgebra - unfold RingHom.toAlgebra' - simp only - rw [toStepOfLE.succ k a a.zero_le] - apply @RingHom.IsIntegral.trans (Step k 0) (Step k a) (Step k (a + 1)) _ _ _ - (toStepOfLE k 0 a (a.zero_le : 0 ≤ a)) (toStepSucc k a) _ - · intro z - convert AdjoinMonic.isIntegral (Step k a) (z : Step k (a + 1)) - · convert h -- Porting note: This times out at 500000 - -instance toStepOfLE.directedSystem : DirectedSystem (Step k) fun i j h => toStepOfLE k i j h := - ⟨fun _ => Nat.leRecOn_self, fun _ _ _ h₁₂ h₂₃ x => (Nat.leRecOn_trans h₁₂ h₂₃ x).symm⟩ - end AlgebraicClosure -/-- Auxiliary construction for `AlgebraicClosure`. Although `AlgebraicClosureAux` does define -the algebraic closure of a field, it is redefined at `AlgebraicClosure` in order to make sure -certain instance diamonds commute by definition. --/ -def AlgebraicClosureAux [Field k] : Type u := - Ring.DirectLimit (AlgebraicClosure.Step k) fun i j h => AlgebraicClosure.toStepOfLE k i j h - -namespace AlgebraicClosureAux - -open AlgebraicClosure - -/-- `AlgebraicClosureAux k` is a `Field` -/ -local instance field : Field (AlgebraicClosureAux k) := - Field.DirectLimit.field _ _ - -instance : Inhabited (AlgebraicClosureAux k) := - ⟨37⟩ - -/-- The canonical ring embedding from the `n`th step to the algebraic closure. -/ -def ofStep (n : ℕ) : Step k n →+* AlgebraicClosureAux k := - Ring.DirectLimit.of _ _ _ - -theorem ofStep_succ (n : ℕ) : (ofStep k (n + 1)).comp (toStepSucc k n) = ofStep k n := by - ext x - have hx : toStepOfLE' k n (n+1) n.le_succ x = toStepSucc k n x := Nat.leRecOn_succ' x - unfold ofStep - rw [RingHom.comp_apply] - dsimp [toStepOfLE] - rw [← hx] - change Ring.DirectLimit.of (Step k) (toStepOfLE' k) (n + 1) (_) = - Ring.DirectLimit.of (Step k) (toStepOfLE' k) n x - convert Ring.DirectLimit.of_f n.le_succ x - -- Porting Note: Original proof timed out at 2 mil. Heartbeats. The problem was likely - -- in comparing `toStepOfLE'` with `toStepSucc`. In the above, I made some things more explicit - -- Original proof: - -- RingHom.ext fun x => - -- show Ring.DirectLimit.of (Step k) (fun i j h => toStepOfLE k i j h) _ _ = _ by - -- convert Ring.DirectLimit.of_f n.le_succ x; ext x; exact (Nat.leRecOn_succ' x).symm - -theorem exists_ofStep (z : AlgebraicClosureAux k) : ∃ n x, ofStep k n x = z := - Ring.DirectLimit.exists_of z - -theorem exists_root {f : Polynomial (AlgebraicClosureAux k)} - (hfm : f.Monic) (hfi : Irreducible f) : ∃ x : AlgebraicClosureAux k, f.eval x = 0 := by - have : ∃ n p, Polynomial.map (ofStep k n) p = f := by - convert Ring.DirectLimit.Polynomial.exists_of f - obtain ⟨n, p, rfl⟩ := this - rw [monic_map_iff] at hfm - have := hfm.irreducible_of_irreducible_map (ofStep k n) p hfi - obtain ⟨x, hx⟩ := toStepSucc.exists_root k hfm this - refine ⟨ofStep k (n + 1) x, ?_⟩ - rw [← ofStep_succ k n, eval_map, ← hom_eval₂, hx, RingHom.map_zero] - -@[local instance] theorem instIsAlgClosed : IsAlgClosed (AlgebraicClosureAux k) := - IsAlgClosed.of_exists_root _ fun _ => exists_root k - -/-- `AlgebraicClosureAux k` is a `k`-`Algebra` -/ -local instance instAlgebra : Algebra k (AlgebraicClosureAux k) := - (ofStep k 0).toAlgebra - -/-- Canonical algebra embedding from the `n`th step to the algebraic closure. -/ -def ofStepHom (n) : Step k n →ₐ[k] AlgebraicClosureAux k := - { ofStep k n with - commutes' := by - -- Porting note: Originally `(fun x => Ring.DirectLimit.of_f n.zero_le x)` - -- I think one problem was in recognizing that we want `toStepOfLE` in `of_f` - intro x - simp only [RingHom.toMonoidHom_eq_coe, OneHom.toFun_eq_coe, MonoidHom.toOneHom_coe, - MonoidHom.coe_coe] - convert @Ring.DirectLimit.of_f ℕ _ (Step k) _ (fun m n h => (toStepOfLE k m n h : _ → _)) - 0 n n.zero_le x } - -instance isAlgebraic : Algebra.IsAlgebraic k (AlgebraicClosureAux k) := - ⟨fun z => - IsIntegral.isAlgebraic <| - let ⟨n, x, hx⟩ := exists_ofStep k z - hx ▸ (Step.isIntegral k n x).map (ofStepHom k n)⟩ - -@[local instance] theorem isAlgClosure : IsAlgClosure k (AlgebraicClosureAux k) := - ⟨AlgebraicClosureAux.instIsAlgClosed k, isAlgebraic k⟩ - -end AlgebraicClosureAux - -attribute [local instance] AlgebraicClosureAux.field AlgebraicClosureAux.instAlgebra - AlgebraicClosureAux.instIsAlgClosed - +open AlgebraicClosure in /-- The canonical algebraic closure of a field, the direct limit of adding roots to the field for each polynomial over the field. -/ @[stacks 09GT] def AlgebraicClosure : Type u := - MvPolynomial (AlgebraicClosureAux k) k ⧸ - RingHom.ker (MvPolynomial.aeval (R := k) id).toRingHom + MvPolynomial (MonicIrreducible k) k ⧸ maxIdeal k namespace AlgebraicClosure @@ -358,21 +116,8 @@ instance {R S : Type*} [CommSemiring R] [CommSemiring S] [Algebra R S] [Algebra [IsScalarTower R S k] : IsScalarTower R S (AlgebraicClosure k) := Ideal.Quotient.isScalarTower _ _ _ -/-- The equivalence between `AlgebraicClosure` and `AlgebraicClosureAux`, which we use to transfer -properties of `AlgebraicClosureAux` to `AlgebraicClosure` -/ -def algEquivAlgebraicClosureAux : - AlgebraicClosure k ≃ₐ[k] AlgebraicClosureAux k := by - delta AlgebraicClosure - exact Ideal.quotientKerAlgEquivOfSurjective - (fun x => ⟨MvPolynomial.X x, by simp⟩) - --- Those two instances are copy-pasta from the analogous instances for `SplittingField` -instance instGroupWithZero : GroupWithZero (AlgebraicClosure k) := - let e := algEquivAlgebraicClosureAux k - { inv := fun a ↦ e.symm (e a)⁻¹ - inv_zero := by simp - mul_inv_cancel := fun a ha ↦ e.injective <| by simp [EmbeddingLike.map_ne_zero_iff.2 ha] - __ := e.surjective.nontrivial } +instance instGroupWithZero : GroupWithZero (AlgebraicClosure k) where + __ := Ideal.Quotient.field _ instance instField : Field (AlgebraicClosure k) where __ := instCommRing _ @@ -389,15 +134,27 @@ instance instField : Field (AlgebraicClosure k) where qsmul_def q x := Quotient.inductionOn x fun p ↦ congr_arg Quotient.mk'' <| by ext; simp [MvPolynomial.algebraMap_eq, Rat.smul_def] -instance isAlgClosed : IsAlgClosed (AlgebraicClosure k) := - IsAlgClosed.of_ringEquiv _ _ (algEquivAlgebraicClosureAux k).symm.toRingEquiv - -instance : IsAlgClosure k (AlgebraicClosure k) := by - rw [isAlgClosure_iff] - exact ⟨inferInstance, (algEquivAlgebraicClosureAux k).symm.isAlgebraic⟩ - instance isAlgebraic : Algebra.IsAlgebraic k (AlgebraicClosure k) := - IsAlgClosure.isAlgebraic + ⟨fun z => + IsIntegral.isAlgebraic <| by + let ⟨p, hp⟩ := Ideal.Quotient.mk_surjective z + rw [← hp] + induction p using MvPolynomial.induction_on generalizing z with + | h_C => exact isIntegral_algebraMap + | h_add _ _ ha hb => exact (ha _ rfl).add (hb _ rfl) + | h_X p f ih => + refine @IsIntegral.mul k _ _ _ _ _ (Ideal.Quotient.mk (maxIdeal k) _) (ih _ rfl) ?_ + refine ⟨f, f.2.1, ?_⟩ + erw [algebraMap, ← hom_eval₂, Ideal.Quotient.eq_zero_iff_mem] + exact le_maxIdeal k (Ideal.subset_span ⟨f, rfl⟩)⟩ + +instance : IsAlgClosure k (AlgebraicClosure k) := .of_exist_roots fun f hfm hfi ↦ + ⟨Ideal.Quotient.mk _ <| MvPolynomial.X (⟨f, hfm, hfi⟩ : MonicIrreducible k), by + -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 + erw [aeval_def, ← hom_eval₂, Ideal.Quotient.eq_zero_iff_mem] + exact le_maxIdeal k (Ideal.subset_span <| ⟨_, rfl⟩)⟩ + +instance isAlgClosed : IsAlgClosed (AlgebraicClosure k) := IsAlgClosure.isAlgClosed k instance [CharZero k] : CharZero (AlgebraicClosure k) := charZero_of_injective_algebraMap (RingHom.injective (algebraMap k (AlgebraicClosure k))) @@ -411,30 +168,3 @@ instance {L : Type*} [Field k] [Field L] [Algebra k L] [Algebra.IsAlgebraic k L] isAlgClosed := inferInstance end AlgebraicClosure - -/-- Over an algebraically closed field of characteristic zero a necessary and sufficient condition -for the set of roots of a nonzero polynomial `f` to be a subset of the set of roots of `g` is that -`f` divides `f.derivative * g`. Over an integral domain, this is a sufficient but not necessary -condition. See `isRoot_of_isRoot_of_dvd_derivative_mul` -/ -theorem Polynomial.isRoot_of_isRoot_iff_dvd_derivative_mul {K : Type*} [Field K] - [IsAlgClosed K] [CharZero K] {f g : K[X]} (hf0 : f ≠ 0) : - (∀ x, IsRoot f x → IsRoot g x) ↔ f ∣ f.derivative * g := by - refine ⟨?_, isRoot_of_isRoot_of_dvd_derivative_mul hf0⟩ - by_cases hg0 : g = 0 - · simp [hg0] - by_cases hdf0 : derivative f = 0 - · rw [eq_C_of_derivative_eq_zero hdf0] - simp only [eval_C, derivative_C, zero_mul, dvd_zero, implies_true] - have hdg : f.derivative * g ≠ 0 := mul_ne_zero hdf0 hg0 - classical rw [Splits.dvd_iff_roots_le_roots (IsAlgClosed.splits f) hf0 hdg, Multiset.le_iff_count] - simp only [count_roots, rootMultiplicity_mul hdg] - refine forall_imp fun a => ?_ - by_cases haf : f.eval a = 0 - · have h0 : 0 < f.rootMultiplicity a := (rootMultiplicity_pos hf0).2 haf - rw [derivative_rootMultiplicity_of_root haf] - intro h - calc rootMultiplicity a f - = rootMultiplicity a f - 1 + 1 := (Nat.sub_add_cancel (Nat.succ_le_iff.1 h0)).symm - _ ≤ rootMultiplicity a f - 1 + rootMultiplicity a g := add_le_add le_rfl (Nat.succ_le_iff.1 - ((rootMultiplicity_pos hg0).2 (h haf))) - · simp [haf, rootMultiplicity_eq_zero haf] diff --git a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean index c164bdbac9521..02cc7fb943f06 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Basic.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Basic.lean @@ -497,3 +497,30 @@ theorem Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits_apply_apply (L : Type*) [F Algebra.IsAlgebraic.algHomEquivAlgHomOfSplits A L hL f x = algebraMap L A (f x) := rfl end Algebra.IsAlgebraic + +/-- Over an algebraically closed field of characteristic zero a necessary and sufficient condition +for the set of roots of a nonzero polynomial `f` to be a subset of the set of roots of `g` is that +`f` divides `f.derivative * g`. Over an integral domain, this is a sufficient but not necessary +condition. See `isRoot_of_isRoot_of_dvd_derivative_mul` -/ +theorem Polynomial.isRoot_of_isRoot_iff_dvd_derivative_mul {K : Type*} [Field K] + [IsAlgClosed K] [CharZero K] {f g : K[X]} (hf0 : f ≠ 0) : + (∀ x, IsRoot f x → IsRoot g x) ↔ f ∣ f.derivative * g := by + refine ⟨?_, isRoot_of_isRoot_of_dvd_derivative_mul hf0⟩ + by_cases hg0 : g = 0 + · simp [hg0] + by_cases hdf0 : derivative f = 0 + · rw [eq_C_of_derivative_eq_zero hdf0] + simp only [eval_C, derivative_C, zero_mul, dvd_zero, implies_true] + have hdg : f.derivative * g ≠ 0 := mul_ne_zero hdf0 hg0 + classical rw [Splits.dvd_iff_roots_le_roots (IsAlgClosed.splits f) hf0 hdg, Multiset.le_iff_count] + simp only [count_roots, rootMultiplicity_mul hdg] + refine forall_imp fun a => ?_ + by_cases haf : f.eval a = 0 + · have h0 : 0 < f.rootMultiplicity a := (rootMultiplicity_pos hf0).2 haf + rw [derivative_rootMultiplicity_of_root haf] + intro h + calc rootMultiplicity a f + = rootMultiplicity a f - 1 + 1 := (Nat.sub_add_cancel (Nat.succ_le_iff.1 h0)).symm + _ ≤ rootMultiplicity a f - 1 + rootMultiplicity a g := add_le_add le_rfl (Nat.succ_le_iff.1 + ((rootMultiplicity_pos hg0).2 (h haf))) + · simp [haf, rootMultiplicity_eq_zero haf] diff --git a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean index 7cd6d8c7278e5..53e821c1bc818 100644 --- a/Mathlib/FieldTheory/IsAlgClosed/Classification.lean +++ b/Mathlib/FieldTheory/IsAlgClosed/Classification.lean @@ -8,7 +8,7 @@ import Mathlib.Algebra.MvPolynomial.Cardinal import Mathlib.Algebra.Polynomial.Cardinal import Mathlib.FieldTheory.IsAlgClosed.Basic import Mathlib.RingTheory.Algebraic.Cardinality -import Mathlib.RingTheory.AlgebraicIndependent +import Mathlib.RingTheory.AlgebraicIndependent.TranscendenceBasis /-! # Classification of Algebraically closed fields diff --git a/Mathlib/FieldTheory/IsPerfectClosure.lean b/Mathlib/FieldTheory/IsPerfectClosure.lean index 5c6d7928dc1a4..db75df108ee8c 100644 --- a/Mathlib/FieldTheory/IsPerfectClosure.lean +++ b/Mathlib/FieldTheory/IsPerfectClosure.lean @@ -96,7 +96,7 @@ theorem mem_pNilradical {R : Type*} [CommSemiring R] {p : ℕ} {x : R} : by_cases hp : 1 < p · rw [pNilradical_eq_nilradical hp] refine ⟨fun ⟨n, h⟩ ↦ ⟨n, ?_⟩, fun ⟨n, h⟩ ↦ ⟨p ^ n, h⟩⟩ - rw [← Nat.sub_add_cancel ((Nat.lt_pow_self hp n).le), pow_add, h, mul_zero] + rw [← Nat.sub_add_cancel ((n.lt_pow_self hp).le), pow_add, h, mul_zero] rw [pNilradical_eq_bot hp, Ideal.mem_bot] refine ⟨fun h ↦ ⟨0, by rw [pow_zero, pow_one, h]⟩, fun ⟨n, h⟩ ↦ ?_⟩ rcases Nat.le_one_iff_eq_zero_or_eq_one.1 (not_lt.1 hp) with hp | hp diff --git a/Mathlib/FieldTheory/KummerExtension.lean b/Mathlib/FieldTheory/KummerExtension.lean index 273c7bd88310d..fee360c7fd681 100644 --- a/Mathlib/FieldTheory/KummerExtension.lean +++ b/Mathlib/FieldTheory/KummerExtension.lean @@ -425,7 +425,7 @@ def adjoinRootXPowSubCEquiv (hζ : (primitiveRoots n K).Nonempty) (H : Irreducib 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, ?_⟩ + refine ⟨(liftHom (X ^ n - C a) α _).injective, ?_⟩ rw [← AlgHom.range_eq_top, ← IsSplittingField.adjoin_rootSet _ (X ^ n - C a), eq_comm, adjoin_rootSet_eq_range, IsSplittingField.adjoin_rootSet] exact IsSplittingField.splits _ _ diff --git a/Mathlib/FieldTheory/Minpoly/Field.lean b/Mathlib/FieldTheory/Minpoly/Field.lean index 6adb8ecfc42d0..e071240005dbf 100644 --- a/Mathlib/FieldTheory/Minpoly/Field.lean +++ b/Mathlib/FieldTheory/Minpoly/Field.lean @@ -5,7 +5,8 @@ Authors: Riccardo Brasca, Johan Commelin -/ import Mathlib.Algebra.Polynomial.FieldDivision import Mathlib.FieldTheory.Minpoly.Basic -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Integral +import Mathlib.RingTheory.LocalRing.Basic /-! # Minimal polynomials on an algebra over a field diff --git a/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean index fae1bec1703c0..cdeabc8d727bf 100644 --- a/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean +++ b/Mathlib/FieldTheory/Minpoly/MinpolyDiv.lean @@ -214,7 +214,7 @@ lemma sum_smul_minpolyDiv_eq_X_pow (E) [Field E] [Algebra K E] [IsAlgClosed E] 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 + exact ((Polynomial.natDegree_smul_le _ _).trans natDegree_map_le).trans_lt ((natDegree_minpolyDiv_lt (Algebra.IsIntegral.isIntegral x)).trans_le (minpoly.natDegree_le _)) · rwa [natDegree_pow, natDegree_X, mul_one, AlgHom.card] diff --git a/Mathlib/FieldTheory/MvRatFunc/Rank.lean b/Mathlib/FieldTheory/MvRatFunc/Rank.lean index e6f6bcac0babe..8843b5d78d6fc 100644 --- a/Mathlib/FieldTheory/MvRatFunc/Rank.lean +++ b/Mathlib/FieldTheory/MvRatFunc/Rank.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jz Pan -/ import Mathlib.Algebra.MvPolynomial.Cardinal -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.LinearIndependent +import Mathlib.RingTheory.Algebraic.MvPolynomial import Mathlib.RingTheory.Localization.Cardinality import Mathlib.RingTheory.MvPolynomial diff --git a/Mathlib/FieldTheory/Normal.lean b/Mathlib/FieldTheory/Normal.lean index dc0da73493444..12486d2a18034 100644 --- a/Mathlib/FieldTheory/Normal.lean +++ b/Mathlib/FieldTheory/Normal.lean @@ -290,6 +290,10 @@ theorem AlgEquiv.restrictNormal_trans [Normal F E] : def AlgEquiv.restrictNormalHom [Normal F E] : (K₁ ≃ₐ[F] K₁) →* E ≃ₐ[F] E := MonoidHom.mk' (fun χ => χ.restrictNormal E) fun ω χ => χ.restrictNormal_trans ω E +lemma AlgEquiv.restrictNormalHom_apply (L : IntermediateField F K₁) [Normal F L] + (σ : (K₁ ≃ₐ[F] K₁)) (x : L) : restrictNormalHom L σ x = σ x := + AlgEquiv.restrictNormal_commutes σ L x + variable (F K₁) /-- If `K₁/E/F` is a tower of fields with `E/F` normal then `AlgHom.restrictNormal'` is an diff --git a/Mathlib/FieldTheory/PerfectClosure.lean b/Mathlib/FieldTheory/PerfectClosure.lean index 6b6f45e166246..7f553815a9734 100644 --- a/Mathlib/FieldTheory/PerfectClosure.lean +++ b/Mathlib/FieldTheory/PerfectClosure.lean @@ -404,7 +404,7 @@ theorem of_apply (x : K) : of K p x = mk _ _ (0, x) := instance instReduced : IsReduced (PerfectClosure K p) where eq_zero x := induction_on x fun x ⟨n, h⟩ ↦ by replace h : mk K p x ^ p ^ n = 0 := by - rw [← Nat.sub_add_cancel ((Nat.lt_pow_self (Fact.out : p.Prime).one_lt n).le), + rw [← Nat.sub_add_cancel ((n.lt_pow_self (Fact.out : p.Prime).one_lt).le), pow_add, h, mul_zero] simp only [zero_def, mk_pow, mk_eq_iff, zero_add, ← coe_iterateFrobenius, map_zero] at h ⊢ obtain ⟨m, h⟩ := h diff --git a/Mathlib/FieldTheory/Relrank.lean b/Mathlib/FieldTheory/Relrank.lean index 6fe6ff6b4ca8b..4c7805692e150 100644 --- a/Mathlib/FieldTheory/Relrank.lean +++ b/Mathlib/FieldTheory/Relrank.lean @@ -35,11 +35,19 @@ variable {E : Type v} [Field E] {L : Type w} [Field L] variable (A B C : Subfield E) +#adaptation_note +/-- +This `synthInstance.maxHeartbeats` (and below) was required after nightly-2024-11-14; +it's not exactly clear why, but we were very close to the limit previously, +so probably we should not particularly blame changes in Lean, and instead optimize in Mathlib. +-/ +set_option synthInstance.maxHeartbeats 400000 in /-- `Subfield.relrank A B` is defined to be `[B : A ⊓ B]` as a `Cardinal`, in particular, when `A ≤ B` it is `[B : A]`, the degree of the field extension `B / A`. This is similar to `Subgroup.relindex` but it is `Cardinal` valued. -/ noncomputable def relrank := Module.rank ↥(A ⊓ B) (extendScalars (inf_le_right : A ⊓ B ≤ B)) +set_option synthInstance.maxHeartbeats 400000 in /-- The `Nat` version of `Subfield.relrank`. If `B / A ⊓ B` is an infinite extension, then it is zero. -/ noncomputable def relfinrank := finrank ↥(A ⊓ B) (extendScalars (inf_le_right : A ⊓ B ≤ B)) @@ -55,12 +63,14 @@ theorem relrank_eq_of_inf_eq (h : A ⊓ C = B ⊓ C) : relrank A C = relrank B C theorem relfinrank_eq_of_inf_eq (h : A ⊓ C = B ⊓ C) : relfinrank A C = relfinrank B C := congr(toNat $(relrank_eq_of_inf_eq h)) +set_option synthInstance.maxHeartbeats 400000 in /-- If `A ≤ B`, then `Subfield.relrank A B` is `[B : A]` -/ theorem relrank_eq_rank_of_le (h : A ≤ B) : relrank A B = Module.rank A (extendScalars h) := by rw [relrank] have := inf_of_le_left h congr! +set_option synthInstance.maxHeartbeats 400000 in /-- If `A ≤ B`, then `Subfield.relfinrank A B` is `[B : A]` -/ theorem relfinrank_eq_finrank_of_le (h : A ≤ B) : relfinrank A B = finrank A (extendScalars h) := congr(toNat $(relrank_eq_rank_of_le h)) @@ -112,6 +122,7 @@ theorem relrank_top_left : relrank ⊤ A = 1 := relrank_eq_one_of_le le_top @[simp] theorem relfinrank_top_left : relfinrank ⊤ A = 1 := relfinrank_eq_one_of_le le_top +set_option synthInstance.maxHeartbeats 400000 in @[simp] theorem relrank_top_right : relrank A ⊤ = Module.rank A E := by rw [relrank_eq_rank_of_le (show A ≤ ⊤ from le_top), extendScalars_top, diff --git a/Mathlib/FieldTheory/Separable.lean b/Mathlib/FieldTheory/Separable.lean index 7488ef0514690..39db5e7df739e 100644 --- a/Mathlib/FieldTheory/Separable.lean +++ b/Mathlib/FieldTheory/Separable.lean @@ -184,7 +184,7 @@ See `PerfectField.separable_iff_squarefree` for the converse when the coefficien field. -/ theorem Separable.squarefree {p : R[X]} (hsep : Separable p) : Squarefree p := by classical - rw [multiplicity.squarefree_iff_emultiplicity_le_one p] + rw [squarefree_iff_emultiplicity_le_one p] exact fun f => or_iff_not_imp_right.mpr fun hunit => emultiplicity_le_one_of_separable hunit hsep end CommSemiring @@ -282,7 +282,7 @@ theorem rootMultiplicity_le_one_of_separable [Nontrivial R] {p : R[X]} (hsep : S by_cases hp : p = 0 · simp [hp] rw [rootMultiplicity_eq_multiplicity, if_neg hp, ← Nat.cast_le (α := ℕ∞), - Nat.cast_one, ← (multiplicity_X_sub_C_finite x hp).emultiplicity_eq_multiplicity] + Nat.cast_one, ← (finiteMultiplicity_X_sub_C x hp).emultiplicity_eq_multiplicity] apply emultiplicity_le_one_of_separable (not_isUnit_X_sub_C _) hsep end CommRing diff --git a/Mathlib/FieldTheory/SeparableDegree.lean b/Mathlib/FieldTheory/SeparableDegree.lean index c6a67370781a2..8cc00db3d0c2b 100644 --- a/Mathlib/FieldTheory/SeparableDegree.lean +++ b/Mathlib/FieldTheory/SeparableDegree.lean @@ -7,7 +7,8 @@ import Mathlib.FieldTheory.SplittingField.Construction import Mathlib.FieldTheory.IsAlgClosed.AlgebraicClosure import Mathlib.FieldTheory.Separable import Mathlib.FieldTheory.NormalClosure -import Mathlib.RingTheory.AlgebraicIndependent +import Mathlib.RingTheory.AlgebraicIndependent.Adjoin +import Mathlib.RingTheory.AlgebraicIndependent.TranscendenceBasis import Mathlib.RingTheory.Polynomial.SeparableDegree import Mathlib.RingTheory.Polynomial.UniqueFactorization @@ -591,7 +592,7 @@ theorem eq_X_pow_char_pow_sub_C_pow_of_natSepDegree_eq_one (q : ℕ) [ExpChar F have hD := (h ▸ natSepDegree_le_of_dvd p f hf hm.ne_zero).antisymm <| Nat.pos_of_ne_zero <| (natSepDegree_ne_zero_iff _).2 hI.natDegree_pos.ne' obtain ⟨n, y, H, hp⟩ := hM.eq_X_pow_char_pow_sub_C_of_natSepDegree_eq_one_of_irreducible q hI hD - have hF := multiplicity_finite_of_degree_pos_of_monic (degree_pos_of_irreducible hI) hM hm.ne_zero + have hF := finiteMultiplicity_of_degree_pos_of_monic (degree_pos_of_irreducible hI) hM hm.ne_zero classical have hne := (multiplicity_pos_of_dvd hf).ne' refine ⟨_, n, y, hne, H, ?_⟩ @@ -778,7 +779,7 @@ theorem finSepDegree_eq_finrank_iff [FiniteDimensional F E] : 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_of_lt_of_le' h (finSepDegree_le_finrank F⟮x⟯ E) Fin.size_pos' + have := Nat.mul_lt_mul_of_lt_of_le' h (finSepDegree_le_finrank F⟮x⟯ E) Fin.pos' rw [finSepDegree_mul_finSepDegree_of_isAlgebraic F F⟮x⟯ E, Module.finrank_mul_finrank F F⟮x⟯ E] at this linarith only [heq, this]⟩, fun _ ↦ finSepDegree_eq_finrank_of_isSeparable F E⟩ diff --git a/Mathlib/FieldTheory/SplittingField/Construction.lean b/Mathlib/FieldTheory/SplittingField/Construction.lean index b9eba35bfa239..5d6be060b9747 100644 --- a/Mathlib/FieldTheory/SplittingField/Construction.lean +++ b/Mathlib/FieldTheory/SplittingField/Construction.lean @@ -5,6 +5,8 @@ Authors: Chris Hughes -/ import Mathlib.Algebra.CharP.Algebra import Mathlib.FieldTheory.SplittingField.IsSplittingField +import Mathlib.RingTheory.Algebraic.Basic +import Mathlib.LinearAlgebra.Dual /-! # Splitting fields diff --git a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean index eb38b5464c6a8..5d6360856ed2d 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Oriented/Affine.lean @@ -46,8 +46,8 @@ def oangle (p₁ p₂ p₃ : P) : Real.Angle := theorem continuousAt_oangle {x : P × P × P} (hx12 : x.1 ≠ x.2.1) (hx32 : x.2.2 ≠ x.2.1) : ContinuousAt (fun y : P × P × P => ∡ y.1 y.2.1 y.2.2) x := by let f : P × P × P → V × V := fun y => (y.1 -ᵥ y.2.1, y.2.2 -ᵥ y.2.1) - have hf1 : (f x).1 ≠ 0 := by simp [hx12] - have hf2 : (f x).2 ≠ 0 := by simp [hx32] + have hf1 : (f x).1 ≠ 0 := by simp [f, hx12] + have hf2 : (f x).2 ≠ 0 := by simp [f, hx32] exact (o.continuousAt_oangle hf1 hf2).comp ((continuous_fst.vsub continuous_snd.fst).prod_mk (continuous_snd.snd.vsub continuous_snd.fst)).continuousAt diff --git a/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean b/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean index 36b42892368e8..782d2803dcdb5 100644 --- a/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean +++ b/Mathlib/Geometry/Euclidean/Angle/Unoriented/Affine.lean @@ -47,8 +47,8 @@ nonrec def angle (p1 p2 p3 : P) : ℝ := theorem continuousAt_angle {x : P × P × P} (hx12 : x.1 ≠ x.2.1) (hx32 : x.2.2 ≠ x.2.1) : ContinuousAt (fun y : P × P × P => ∠ y.1 y.2.1 y.2.2) x := by let f : P × P × P → V × V := fun y => (y.1 -ᵥ y.2.1, y.2.2 -ᵥ y.2.1) - have hf1 : (f x).1 ≠ 0 := by simp [hx12] - have hf2 : (f x).2 ≠ 0 := by simp [hx32] + have hf1 : (f x).1 ≠ 0 := by simp [f, hx12] + have hf2 : (f x).2 ≠ 0 := by simp [f, hx32] exact (InnerProductGeometry.continuousAt_angle hf1 hf2).comp ((continuous_fst.vsub continuous_snd.fst).prod_mk (continuous_snd.snd.vsub continuous_snd.fst)).continuousAt diff --git a/Mathlib/Geometry/Euclidean/Basic.lean b/Mathlib/Geometry/Euclidean/Basic.lean index d39b79aad2703..f708b2d5f2073 100644 --- a/Mathlib/Geometry/Euclidean/Basic.lean +++ b/Mathlib/Geometry/Euclidean/Basic.lean @@ -472,14 +472,14 @@ general sense of the word that includes both those common cases. -/ def reflection (s : AffineSubspace ℝ P) [Nonempty s] [HasOrthogonalProjection s.direction] : P ≃ᵃⁱ[ℝ] P := AffineIsometryEquiv.mk' - (fun p => ↑(orthogonalProjection s p) -ᵥ p +ᵥ (orthogonalProjection s p : P)) + (fun p => (↑(orthogonalProjection s p) -ᵥ p) +ᵥ (orthogonalProjection s p : P)) (_root_.reflection s.direction) (↑(Classical.arbitrary s)) (by intro p let v := p -ᵥ ↑(Classical.arbitrary s) let a : V := _root_.orthogonalProjection s.direction v let b : P := ↑(Classical.arbitrary s) - have key : a +ᵥ b -ᵥ (v +ᵥ b) +ᵥ (a +ᵥ b) = a + a - v +ᵥ (b -ᵥ b +ᵥ b) := by + have key : ((a +ᵥ b) -ᵥ (v +ᵥ b)) +ᵥ (a +ᵥ b) = (a + a - v) +ᵥ (b -ᵥ b) +ᵥ b := by rw [← add_vadd, vsub_vadd_eq_vsub_sub, vsub_vadd, vadd_vsub] congr 1 abel @@ -489,7 +489,8 @@ def reflection (s : AffineSubspace ℝ P) [Nonempty s] [HasOrthogonalProjection /-- The result of reflecting. -/ theorem reflection_apply (s : AffineSubspace ℝ P) [Nonempty s] [HasOrthogonalProjection s.direction] - (p : P) : reflection s p = ↑(orthogonalProjection s p) -ᵥ p +ᵥ (orthogonalProjection s p : P) := + (p : P) : + reflection s p = (↑(orthogonalProjection s p) -ᵥ p) +ᵥ (orthogonalProjection s p : P) := rfl theorem eq_reflection_of_eq_subspace {s s' : AffineSubspace ℝ P} [Nonempty s] [Nonempty s'] diff --git a/Mathlib/Geometry/Euclidean/Circumcenter.lean b/Mathlib/Geometry/Euclidean/Circumcenter.lean index dd63de61c9efd..a2bd062cbe191 100644 --- a/Mathlib/Geometry/Euclidean/Circumcenter.lean +++ b/Mathlib/Geometry/Euclidean/Circumcenter.lean @@ -645,7 +645,7 @@ theorem reflection_circumcenter_eq_affineCombination_of_pointsWithCircumcenter { (orthogonalProjection W s.circumcenter : P) = ↑((s.face hc).orthogonalProjectionSpan s.circumcenter) := by apply eq_orthogonalProjection_of_eq_subspace - simp + simp [W] rw [EuclideanGeometry.reflection_apply, h_faces, s.orthogonalProjection_circumcenter hc, circumcenter_eq_centroid, s.face_centroid_eq_centroid hc, centroid_eq_affineCombination_of_pointsWithCircumcenter, diff --git a/Mathlib/Geometry/Euclidean/MongePoint.lean b/Mathlib/Geometry/Euclidean/MongePoint.lean index c3bf888133c63..9800925e6fb48 100644 --- a/Mathlib/Geometry/Euclidean/MongePoint.lean +++ b/Mathlib/Geometry/Euclidean/MongePoint.lean @@ -220,9 +220,9 @@ theorem inner_mongePoint_vsub_face_centroid_vsub {n : ℕ} (s : Simplex ℝ P (n · simp_rw [sum_pointsWithCircumcenter, pointsWithCircumcenter_eq_circumcenter, pointsWithCircumcenter_point, Pi.sub_apply, pointWeightsWithCircumcenter] rw [← sum_subset fs.subset_univ _] - · simp_rw [sum_insert (not_mem_singleton.2 h), sum_singleton] + · simp_rw [fs, sum_insert (not_mem_singleton.2 h), sum_singleton] repeat rw [← sum_subset fs.subset_univ _] - · simp_rw [sum_insert (not_mem_singleton.2 h), sum_singleton] + · simp_rw [fs, sum_insert (not_mem_singleton.2 h), sum_singleton] simp [h, Ne.symm h, dist_comm (s.points i₁)] all_goals intro i _ hi; simp [hfs i hi] · intro i _ hi @@ -442,12 +442,8 @@ theorem orthocenter_eq_of_range_eq {t₁ t₂ : Triangle ℝ P} planes. -/ theorem altitude_eq_mongePlane (t : Triangle ℝ P) {i₁ i₂ i₃ : Fin 3} (h₁₂ : i₁ ≠ i₂) (h₁₃ : i₁ ≠ i₃) (h₂₃ : i₂ ≠ i₃) : t.altitude i₁ = t.mongePlane i₂ i₃ := by - have hs : ({i₂, i₃}ᶜ : Finset (Fin 3)) = {i₁} := by - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert i₁ i₂ i₃; decide - have he : univ.erase i₁ = {i₂, i₃} := by - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert i₁ i₂ i₃; decide + have hs : ({i₂, i₃}ᶜ : Finset (Fin 3)) = {i₁} := by decide +revert + have he : univ.erase i₁ = {i₂, i₃} := by decide +revert rw [mongePlane_def, altitude_def, direction_affineSpan, hs, he, centroid_singleton, coe_insert, coe_singleton, vectorSpan_image_eq_span_vsub_set_left_ne ℝ _ (Set.mem_insert i₂ _)] simp [h₂₃, Submodule.span_insert_eq_span] @@ -456,8 +452,7 @@ theorem altitude_eq_mongePlane (t : Triangle ℝ P) {i₁ i₂ i₃ : Fin 3} (h theorem orthocenter_mem_altitude (t : Triangle ℝ P) {i₁ : Fin 3} : t.orthocenter ∈ t.altitude i₁ := by obtain ⟨i₂, i₃, h₁₂, h₂₃, h₁₃⟩ : ∃ i₂ i₃, i₁ ≠ i₂ ∧ i₂ ≠ i₃ ∧ i₁ ≠ i₃ := by - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - fin_cases i₁ <;> decide + decide +revert rw [orthocenter_eq_mongePoint, t.altitude_eq_mongePlane h₁₂ h₁₃ h₂₃] exact t.mongePoint_mem_mongePlane @@ -467,8 +462,7 @@ theorem eq_orthocenter_of_forall_mem_altitude {t : Triangle ℝ P} {i₁ i₂ : (h₁₂ : i₁ ≠ i₂) (h₁ : p ∈ t.altitude i₁) (h₂ : p ∈ t.altitude i₂) : p = t.orthocenter := by obtain ⟨i₃, h₂₃, h₁₃⟩ : ∃ i₃, i₂ ≠ i₃ ∧ i₁ ≠ i₃ := by clear h₁ h₂ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - fin_cases i₁ <;> fin_cases i₂ <;> decide + decide +revert rw [t.altitude_eq_mongePlane h₁₃ h₁₂ h₂₃.symm] at h₁ rw [t.altitude_eq_mongePlane h₂₃ h₁₂.symm h₁₃.symm] at h₂ rw [orthocenter_eq_mongePoint] @@ -476,8 +470,7 @@ theorem eq_orthocenter_of_forall_mem_altitude {t : Triangle ℝ P} {i₁ i₂ : intro i hi have hi₁₂ : i₁ = i ∨ i₂ = i := by clear h₁ h₂ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - fin_cases i₁ <;> fin_cases i₂ <;> fin_cases i₃ <;> fin_cases i <;> simp at h₁₂ h₁₃ h₂₃ hi ⊢ + decide +revert cases' hi₁₂ with hi₁₂ hi₁₂ · exact hi₁₂ ▸ h₂ · exact hi₁₂ ▸ h₁ @@ -498,8 +491,7 @@ theorem dist_orthocenter_reflection_circumcenter (t : Triangle ℝ P) {i₁ i₂ have hu : ({i₁, i₂} : Finset (Fin 3)) ⊆ univ := subset_univ _ obtain ⟨i₃, hi₃, hi₃₁, hi₃₂⟩ : ∃ i₃, univ \ ({i₁, i₂} : Finset (Fin 3)) = {i₃} ∧ i₃ ≠ i₁ ∧ i₃ ≠ i₂ := by - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - fin_cases i₁ <;> fin_cases i₂ <;> simp at h <;> decide + decide +revert simp_rw [← sum_sdiff hu, hi₃] norm_num [hi₃₁, hi₃₂] @@ -542,8 +534,7 @@ theorem altitude_replace_orthocenter_eq_affineSpan {t₁ t₂ : Triangle ℝ P} ?_ · have hu : (Finset.univ : Finset (Fin 3)) = {j₁, j₂, j₃} := by clear h₁ h₂ h₃ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert i₁ i₂ i₃ j₁ j₂ j₃; decide + decide +revert rw [← Set.image_univ, ← Finset.coe_univ, hu, Finset.coe_insert, Finset.coe_insert, Finset.coe_singleton, Set.image_insert_eq, Set.image_insert_eq, Set.image_singleton, h₁, h₂, h₃, Set.insert_subset_iff, Set.insert_subset_iff, Set.singleton_subset_iff] @@ -557,16 +548,14 @@ theorem altitude_replace_orthocenter_eq_affineSpan {t₁ t₂ : Triangle ℝ P} use mem_affineSpan ℝ (Set.mem_range_self _) have hu : Finset.univ.erase j₂ = {j₁, j₃} := by clear h₁ h₂ h₃ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert i₁ i₂ i₃ j₁ j₂ j₃; decide + decide +revert rw [hu, Finset.coe_insert, Finset.coe_singleton, Set.image_insert_eq, Set.image_singleton, h₁, h₃] have hle : (t₁.altitude i₃).directionᗮ ≤ line[ℝ, t₁.orthocenter, t₁.points i₃].directionᗮ := Submodule.orthogonal_le (direction_le (affineSpan_orthocenter_point_le_altitude _ _)) refine hle ((t₁.vectorSpan_isOrtho_altitude_direction i₃) ?_) have hui : Finset.univ.erase i₃ = {i₁, i₂} := by clear hle h₂ h₃ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert i₁ i₂ i₃; decide + decide +revert rw [hui, Finset.coe_insert, Finset.coe_singleton, Set.image_insert_eq, Set.image_singleton] exact vsub_mem_vectorSpan ℝ (Set.mem_insert _ _) (Set.mem_insert_of_mem _ (Set.mem_singleton _)) @@ -622,7 +611,7 @@ theorem exists_of_range_subset_orthocentricSystem {t : Triangle ℝ P} obtain ⟨i₂, i₃, h₁₂, h₁₃, h₂₃, h₁₂₃⟩ : ∃ i₂ i₃ : Fin 3, i₁ ≠ i₂ ∧ i₁ ≠ i₃ ∧ i₂ ≠ i₃ ∧ ∀ i : Fin 3, i = i₁ ∨ i = i₂ ∨ i = i₃ := by clear h₁ - fin_cases i₁ <;> decide + decide +revert have h : ∀ i, i₁ ≠ i → ∃ j : Fin 3, t.points j = p i := by intro i hi replace hps := Set.mem_of_mem_insert_of_ne @@ -729,8 +718,7 @@ theorem OrthocentricSystem.eq_insert_orthocenter {s : Set P} (ho : OrthocentricS · obtain ⟨j₁, hj₁₂, hj₁₃, hj₁₂₃⟩ : ∃ j₁ : Fin 3, j₁ ≠ j₂ ∧ j₁ ≠ j₃ ∧ ∀ j : Fin 3, j = j₁ ∨ j = j₂ ∨ j = j₃ := by clear h₂ h₃ - -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11043): was `decide!` - revert j₂ j₃; decide + decide +revert suffices h : t₀.points j₁ = t.orthocenter by have hui : (Set.univ : Set (Fin 3)) = {i₁, i₂, i₃} := by ext x; simpa using h₁₂₃ x have huj : (Set.univ : Set (Fin 3)) = {j₁, j₂, j₃} := by ext x; simpa using hj₁₂₃ x diff --git a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean index c9dd661d44afd..2997b5c92169b 100644 --- a/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean +++ b/Mathlib/Geometry/Manifold/Algebra/LieGroup.lean @@ -204,15 +204,14 @@ class SmoothInv₀ {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [To /-- Inversion is smooth away from `0`. -/ smoothAt_inv₀ : ∀ ⦃x : G⦄, x ≠ 0 → ContMDiffAt I I ⊤ (fun y ↦ y⁻¹) x -instance {𝕜 : Type*} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] : SmoothInv₀ 𝓘(𝕜) 𝕜 := - { smoothAt_inv₀ := by - intro x hx - change ContMDiffAt 𝓘(𝕜) 𝓘(𝕜) ⊤ Inv.inv x - rw [contMDiffAt_iff_contDiffAt] - exact contDiffAt_inv 𝕜 hx } +instance {𝕜 : Type*} [NontriviallyNormedField 𝕜] : SmoothInv₀ 𝓘(𝕜) 𝕜 where + smoothAt_inv₀ x hx := by + change ContMDiffAt 𝓘(𝕜) 𝓘(𝕜) ⊤ Inv.inv x + rw [contMDiffAt_iff_contDiffAt] + exact contDiffAt_inv 𝕜 hx variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] {H : Type*} [TopologicalSpace H] {E : Type*} - [NormedAddCommGroup E] [NormedSpace 𝕜 E] (I : ModelWithCorners 𝕜 E H) {G : Type*} + [NormedAddCommGroup E] [NormedSpace 𝕜 E] {I : ModelWithCorners 𝕜 E H} {G : Type*} [TopologicalSpace G] [ChartedSpace H G] [Inv G] [Zero G] [SmoothInv₀ I G] {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] {H' : Type*} [TopologicalSpace H'] {I' : ModelWithCorners 𝕜 E' H'} {M : Type*} [TopologicalSpace M] [ChartedSpace H' M] @@ -228,23 +227,23 @@ include I in This is not an instance for technical reasons, see note [Design choices about smooth algebraic structures]. -/ theorem hasContinuousInv₀_of_hasSmoothInv₀ : HasContinuousInv₀ G := - { continuousAt_inv₀ := fun _ hx ↦ (contMDiffAt_inv₀ I hx).continuousAt } + { continuousAt_inv₀ := fun _ hx ↦ (contMDiffAt_inv₀ (I := I) hx).continuousAt } theorem contMDiffOn_inv₀ : ContMDiffOn I I ⊤ (Inv.inv : G → G) {0}ᶜ := fun _x hx => - (contMDiffAt_inv₀ I hx).contMDiffWithinAt + (contMDiffAt_inv₀ hx).contMDiffWithinAt @[deprecated (since := "2024-11-21")] alias smoothOn_inv₀ := contMDiffOn_inv₀ @[deprecated (since := "2024-11-21")] alias SmoothOn_inv₀ := contMDiffOn_inv₀ -variable {I} {s : Set M} {a : M} +variable {s : Set M} {a : M} theorem ContMDiffWithinAt.inv₀ (hf : ContMDiffWithinAt I' I n f s a) (ha : f a ≠ 0) : ContMDiffWithinAt I' I n (fun x => (f x)⁻¹) s a := - ((contMDiffAt_inv₀ I ha).of_le le_top).comp_contMDiffWithinAt a hf + ((contMDiffAt_inv₀ ha).of_le le_top).comp_contMDiffWithinAt a hf theorem ContMDiffAt.inv₀ (hf : ContMDiffAt I' I n f a) (ha : f a ≠ 0) : ContMDiffAt I' I n (fun x ↦ (f x)⁻¹) a := - ((contMDiffAt_inv₀ I ha).of_le le_top).comp a hf + ((contMDiffAt_inv₀ ha).of_le le_top).comp a hf theorem ContMDiff.inv₀ (hf : ContMDiff I' I n f) (h0 : ∀ x, f x ≠ 0) : ContMDiff I' I n (fun x ↦ (f x)⁻¹) := diff --git a/Mathlib/Geometry/Manifold/AnalyticManifold.lean b/Mathlib/Geometry/Manifold/AnalyticManifold.lean index ea26292a58a0d..cecf164328810 100644 --- a/Mathlib/Geometry/Manifold/AnalyticManifold.lean +++ b/Mathlib/Geometry/Manifold/AnalyticManifold.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Lee, Geoffrey Irving -/ import Mathlib.Analysis.Analytic.Constructions -import Mathlib.Analysis.Calculus.ContDiff.Analytic import Mathlib.Geometry.Manifold.SmoothManifoldWithCorners /-! @@ -15,9 +14,6 @@ half-space (to get manifolds with boundaries) for which changes of coordinates a interior and smooth everywhere (including at the boundary). The definition mirrors `SmoothManifoldWithCorners`, but using an `analyticGroupoid` in place of `contDiffGroupoid`. All analytic manifolds are smooth manifolds. - -Completeness is required throughout, but this is nonessential: it is due to many of the lemmas about -AnalyticOn` requiring completeness for ease of proof. -/ noncomputable section @@ -167,11 +163,10 @@ instance AnalyticManifold.prod {E A : Type} [NormedAddCommGroup E] [NormedSpace /-- Analytic manifolds are smooth manifolds. -/ instance AnalyticManifold.smoothManifoldWithCorners [ChartedSpace H M] - [cm : AnalyticManifold I M] [CompleteSpace E] : + [cm : AnalyticManifold I M] : SmoothManifoldWithCorners I M where - compatible := by - intro f g hf hg - have m := cm.compatible hf hg - exact ⟨m.1.contDiffOn, m.2.contDiffOn⟩ + compatible hf hg := ⟨(cm.compatible hf hg).1.contDiffOn I.uniqueDiffOn_preimage_source, + (cm.compatible hg hf).1.contDiffOn I.uniqueDiffOn_preimage_source⟩ + end AnalyticManifold diff --git a/Mathlib/Geometry/Manifold/ChartedSpace.lean b/Mathlib/Geometry/Manifold/ChartedSpace.lean index 93c0039fd5c2f..0e455da5da7e2 100644 --- a/Mathlib/Geometry/Manifold/ChartedSpace.lean +++ b/Mathlib/Geometry/Manifold/ChartedSpace.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ import Mathlib.Topology.PartialHomeomorph +import Mathlib.Topology.Connected.PathConnected /-! # Charted spaces @@ -693,6 +694,23 @@ theorem ChartedSpace.locallyConnectedSpace [LocallyConnectedSpace H] : LocallyCo · rintro x s ⟨⟨-, -, hsconn⟩, hssubset⟩ exact hsconn.isPreconnected.image _ ((e x).continuousOn_symm.mono hssubset) +/-- If a topological space `M` admits an atlas with locally path-connected charts, + then `M` itself is locally path-connected. -/ +theorem ChartedSpace.locPathConnectedSpace [LocPathConnectedSpace H] : LocPathConnectedSpace M := by + refine ⟨fun x ↦ ⟨fun s ↦ ⟨fun hs ↦ ?_, fun ⟨u, hu⟩ ↦ Filter.mem_of_superset hu.1.1 hu.2⟩⟩⟩ + let e := chartAt H x + let t := s ∩ e.source + have ht : t ∈ 𝓝 x := Filter.inter_mem hs (chart_source_mem_nhds _ _) + refine ⟨e.symm '' pathComponentIn (e x) (e '' t), ⟨?_, ?_⟩, (?_ : _ ⊆ t).trans inter_subset_left⟩ + · nth_rewrite 1 [← e.left_inv (mem_chart_source _ _)] + apply e.symm.image_mem_nhds (by simp [e]) + exact pathComponentIn_mem_nhds <| e.image_mem_nhds (mem_chart_source _ _) ht + · refine (isPathConnected_pathComponentIn <| mem_image_of_mem e (mem_of_mem_nhds ht)).image' ?_ + refine e.continuousOn_symm.mono <| subset_trans ?_ e.map_source'' + exact (pathComponentIn_mono <| image_mono inter_subset_right).trans pathComponentIn_subset + · exact (image_mono pathComponentIn_subset).trans + (PartialEquiv.symm_image_image_of_subset_source _ inter_subset_right).subset + /-- If `M` is modelled on `H'` and `H'` is itself modelled on `H`, then we can consider `M` as being modelled on `H`. -/ def ChartedSpace.comp (H : Type*) [TopologicalSpace H] (H' : Type*) [TopologicalSpace H'] @@ -1051,6 +1069,10 @@ theorem StructureGroupoid.mem_maximalAtlas_of_mem_groupoid {f : PartialHomeomorp rintro e (rfl : e = PartialHomeomorph.refl H) exact ⟨G.trans (G.symm hf) G.id_mem, G.trans (G.symm G.id_mem) hf⟩ +theorem StructureGroupoid.maximalAtlas_mono {G G' : StructureGroupoid H} (h : G ≤ G') : + G.maximalAtlas M ⊆ G'.maximalAtlas M := + fun _ he e' he' ↦ ⟨h (he e' he').1, h (he e' he').2⟩ + end MaximalAtlas section Singleton diff --git a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean index 49996ee7ba8cb..3ab6587a89afc 100644 --- a/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean +++ b/Mathlib/Geometry/Manifold/ContMDiff/Defs.lean @@ -479,6 +479,21 @@ theorem contMDiffOn_iff : convert hdiff x (f x) (extChartAt I x x) (by simp only [hx, mfld_simps]) using 1 mfld_set_tac +/-- zero-smoothness on a set is equivalent to continuity on this set. -/ +theorem contMDiffOn_zero_iff : + ContMDiffOn I I' 0 f s ↔ ContinuousOn f s := by + rw [contMDiffOn_iff] + refine ⟨fun h ↦ h.1, fun h ↦ ⟨h, ?_⟩⟩ + intro x y + rw [show ((0 : ℕ∞) : WithTop ℕ∞) = 0 by rfl, contDiffOn_zero] + apply (continuousOn_extChartAt _).comp + · apply h.comp ((continuousOn_extChartAt_symm _).mono inter_subset_left) (fun z hz ↦ ?_) + simp only [preimage_inter, mem_inter_iff, mem_preimage] at hz + exact hz.2.1 + · intro z hz + simp only [preimage_inter, mem_inter_iff, mem_preimage] at hz + exact hz.2.2 + /-- One can reformulate smoothness on a set as continuity on this set, and smoothness in any extended chart in the target. -/ theorem contMDiffOn_iff_target : @@ -525,6 +540,11 @@ theorem contMDiff_iff_target : @[deprecated (since := "2024-11-20")] alias smooth_iff_target := contMDiff_iff_target +/-- zero-smoothness is equivalent to continuity. -/ +theorem contMDiff_zero_iff : + ContMDiff I I' 0 f ↔ Continuous f := by + rw [← contMDiffOn_univ, continuous_iff_continuousOn_univ, contMDiffOn_zero_iff] + end SmoothManifoldWithCorners /-! ### Deducing smoothness from smoothness one step beyond -/ @@ -563,8 +583,8 @@ theorem ContMDiff.continuous (hf : ContMDiff I I' n f) : Continuous f := theorem contMDiffWithinAt_top : ContMDiffWithinAt I I' ⊤ f s x ↔ ∀ n : ℕ, ContMDiffWithinAt I I' n f s x := - ⟨fun h n => ⟨h.1, contDiffWithinAt_top.1 h.2 n⟩, fun H => - ⟨(H 0).1, contDiffWithinAt_top.2 fun n => (H n).2⟩⟩ + ⟨fun h n => ⟨h.1, contDiffWithinAt_infty.1 h.2 n⟩, fun H => + ⟨(H 0).1, contDiffWithinAt_infty.2 fun n => (H n).2⟩⟩ theorem contMDiffAt_top : ContMDiffAt I I' ⊤ f x ↔ ∀ n : ℕ, ContMDiffAt I I' n f x := contMDiffWithinAt_top @@ -690,7 +710,7 @@ theorem contMDiffWithinAt_iff_contMDiffOn_nhds (hu _ (mem_of_mem_nhdsWithin hxs hmem)).mono_of_mem_nhdsWithin hmem⟩ -- The property is true in charts. Let `v` be a good neighborhood in the chart where the function -- is smooth. - rcases (contMDiffWithinAt_iff'.1 h).2.contDiffOn le_rfl with ⟨v, hmem, hsub, hv⟩ + rcases (contMDiffWithinAt_iff'.1 h).2.contDiffOn le_rfl (by simp) with ⟨v, hmem, hsub, hv⟩ have hxs' : extChartAt I x x ∈ (extChartAt I x).target ∩ (extChartAt I x).symm ⁻¹' (s ∩ f ⁻¹' (extChartAt I' (f x)).source) := ⟨(extChartAt I x).map_source (mem_extChartAt_source _), by rwa [extChartAt_to_inv], by diff --git a/Mathlib/Geometry/Manifold/Diffeomorph.lean b/Mathlib/Geometry/Manifold/Diffeomorph.lean index 6a6dd316cf875..ed39ae6e822cd 100644 --- a/Mathlib/Geometry/Manifold/Diffeomorph.lean +++ b/Mathlib/Geometry/Manifold/Diffeomorph.lean @@ -79,13 +79,11 @@ scoped[Manifold] notation M " ≃ₘ^" n:1000 "⟮" I ", " J "⟯ " N => Diffeom scoped[Manifold] notation M " ≃ₘ⟮" I ", " J "⟯ " N => Diffeomorph I J M N ⊤ /-- `n`-times continuously differentiable diffeomorphism between `E` and `E'`. -/ -scoped[Manifold] - notation E " ≃ₘ^" n:1000 "[" 𝕜 "] " E' => - Diffeomorph (modelWithCornersSelf 𝕜 E) (modelWithCornersSelf 𝕜 E') E E' n +scoped[Manifold] notation E " ≃ₘ^" n:1000 "[" 𝕜 "] " E' => Diffeomorph 𝓘(𝕜, E) 𝓘(𝕜, E') E E' n /-- Infinitely differentiable diffeomorphism between `E` and `E'`. -/ scoped[Manifold] - notation E " ≃ₘ[" 𝕜 "] " E' => + notation3 E " ≃ₘ[" 𝕜 "] " E' => Diffeomorph (modelWithCornersSelf 𝕜 E) (modelWithCornersSelf 𝕜 E') E E' ⊤ namespace Diffeomorph diff --git a/Mathlib/Geometry/Manifold/Instances/Real.lean b/Mathlib/Geometry/Manifold/Instances/Real.lean index ce5fb5a376760..3bea4b00685c4 100644 --- a/Mathlib/Geometry/Manifold/Instances/Real.lean +++ b/Mathlib/Geometry/Manifold/Instances/Real.lean @@ -14,16 +14,18 @@ or with boundary or with corners. As a concrete example, we construct explicitly boundary structure on the real interval `[x, y]`. More specifically, we introduce -* `ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)` for the model space +* `modelWithCornersEuclideanHalfSpace n : + ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)` for the model space used to define `n`-dimensional real manifolds with boundary -* `ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanQuadrant n)` for the model space used +* `modelWithCornersEuclideanQuadrant n : + ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanQuadrant n)` for the model space used to define `n`-dimensional real manifolds with corners ## Notations In the locale `Manifold`, we introduce the notations * `𝓡 n` for the identity model with corners on `EuclideanSpace ℝ (Fin n)` -* `𝓡∂ n` for `ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)`. +* `𝓡∂ n` for `modelWithCornersEuclideanHalfSpace n`. For instance, if a manifold `M` is boundaryless, smooth and modelled on `EuclideanSpace ℝ (Fin m)`, and `N` is smooth with boundary modelled on `EuclideanHalfSpace n`, and `f : M → N` is a smooth @@ -85,6 +87,27 @@ theorem EuclideanHalfSpace.ext [NeZero n] (x y : EuclideanHalfSpace n) (h : x.1 = y.1) : x = y := Subtype.eq h +theorem EuclideanHalfSpace.convex [NeZero n] : + Convex ℝ { x : EuclideanSpace ℝ (Fin n) | 0 ≤ x 0 } := + fun _ hx _ hy _ _ _ _ _ ↦ by dsimp at hx hy ⊢; positivity + +theorem EuclideanQuadrant.convex : + Convex ℝ { x : EuclideanSpace ℝ (Fin n) | ∀ i, 0 ≤ x i } := + fun _ hx _ hy _ _ _ _ _ i ↦ by dsimp at hx hy ⊢; specialize hx i; specialize hy i; positivity + +instance EuclideanHalfSpace.pathConnectedSpace [NeZero n] : + PathConnectedSpace (EuclideanHalfSpace n) := + isPathConnected_iff_pathConnectedSpace.mp <| convex.isPathConnected ⟨0, by simp⟩ + +instance EuclideanQuadrant.pathConnectedSpace : PathConnectedSpace (EuclideanQuadrant n) := + isPathConnected_iff_pathConnectedSpace.mp <| convex.isPathConnected ⟨0, by simp⟩ + +instance [NeZero n] : LocPathConnectedSpace (EuclideanHalfSpace n) := + EuclideanHalfSpace.convex.locPathConnectedSpace + +instance : LocPathConnectedSpace (EuclideanQuadrant n) := + EuclideanQuadrant.convex.locPathConnectedSpace + theorem range_euclideanHalfSpace (n : ℕ) [NeZero n] : (range fun x : EuclideanHalfSpace n => x.val) = { y | 0 ≤ y 0 } := Subtype.range_val @@ -98,6 +121,7 @@ theorem interior_halfSpace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) : change interior (f ⁻¹' Ici a) = f ⁻¹' Ioi a rw [f.interior_preimage, interior_Ici] apply Function.surjective_eval + @[deprecated (since := "2024-11-12")] alias interior_halfspace := interior_halfSpace open ENNReal in @@ -108,6 +132,7 @@ theorem closure_halfSpace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) : change closure (f ⁻¹' Ici a) = f ⁻¹' Ici a rw [f.closure_preimage, closure_Ici] apply Function.surjective_eval + @[deprecated (since := "2024-11-12")] alias closure_halfspace := closure_halfSpace open ENNReal in @@ -118,6 +143,7 @@ theorem closure_open_halfSpace {n : ℕ} (p : ℝ≥0∞) (a : ℝ) (i : Fin n) change closure (f ⁻¹' Ioi a) = f ⁻¹' Ici a rw [f.closure_preimage, closure_Ioi] apply Function.surjective_eval + @[deprecated (since := "2024-11-12")] alias closure_open_halfspace := closure_open_halfSpace open ENNReal in @@ -193,13 +219,13 @@ def modelWithCornersEuclideanQuadrant (n : ℕ) : /-- The model space used to define `n`-dimensional real manifolds without boundary. -/ scoped[Manifold] - notation "𝓡 " n => + notation3 "𝓡 " n => (modelWithCornersSelf ℝ (EuclideanSpace ℝ (Fin n)) : ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanSpace ℝ (Fin n))) /-- The model space used to define `n`-dimensional real manifolds with boundary. -/ scoped[Manifold] - notation "𝓡∂ " n => + notation3 "𝓡∂ " n => (modelWithCornersEuclideanHalfSpace n : ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)) diff --git a/Mathlib/Geometry/Manifold/Instances/Sphere.lean b/Mathlib/Geometry/Manifold/Instances/Sphere.lean index a426774e69c58..abc2d5450eb3b 100644 --- a/Mathlib/Geometry/Manifold/Instances/Sphere.lean +++ b/Mathlib/Geometry/Manifold/Instances/Sphere.lean @@ -4,10 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Heather Macbeth -/ import Mathlib.Analysis.Calculus.Deriv.Inv +import Mathlib.Analysis.Complex.Circle import Mathlib.Analysis.NormedSpace.BallAction import Mathlib.Analysis.SpecialFunctions.ExpDeriv import Mathlib.Analysis.InnerProductSpace.Calculus import Mathlib.Analysis.InnerProductSpace.PiL2 +import Mathlib.Data.Complex.FiniteDimensional import Mathlib.Geometry.Manifold.Algebra.LieGroup import Mathlib.Geometry.Manifold.Instances.Real import Mathlib.Geometry.Manifold.MFDeriv.Basic diff --git a/Mathlib/Geometry/Manifold/IntegralCurve/ExistUnique.lean b/Mathlib/Geometry/Manifold/IntegralCurve/ExistUnique.lean index 8960304376097..bb586ece1fb8e 100644 --- a/Mathlib/Geometry/Manifold/IntegralCurve/ExistUnique.lean +++ b/Mathlib/Geometry/Manifold/IntegralCurve/ExistUnique.lean @@ -162,7 +162,7 @@ theorem isIntegralCurveAt_eventuallyEq_of_contMDiffAt (hγt₀ : I.IsInteriorPoi -- main proof suffices (extChartAt I (γ t₀)) ∘ γ =ᶠ[𝓝 t₀] (extChartAt I (γ' t₀)) ∘ γ' from (heq hγ).trans <| (this.fun_comp (extChartAt I (γ t₀)).symm).trans (h ▸ (heq hγ').symm) - exact ODE_solution_unique_of_eventually hlip + exact ODE_solution_unique_of_eventually (.of_forall hlip) (hdrv hγ rfl) (hdrv hγ' h) (by rw [Function.comp_apply, Function.comp_apply, h]) theorem isIntegralCurveAt_eventuallyEq_of_contMDiffAt_boundaryless [BoundarylessManifold I M] diff --git a/Mathlib/Geometry/Manifold/MFDeriv/NormedSpace.lean b/Mathlib/Geometry/Manifold/MFDeriv/NormedSpace.lean index 7b650ffa5716c..2e727c4ef5022 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/NormedSpace.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/NormedSpace.lean @@ -79,21 +79,35 @@ theorem Differentiable.comp_mdifferentiable {g : F → F'} {f : M → F} (hg : D end Module -/-! ### Linear maps between normed spaces are smooth -/ +/-! ### Linear maps between normed spaces are differentiable -/ +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6024 +we needed to add the named arguments `𝕜 := 𝕜` and `F := ((F₂ →L[𝕜] F₃) →L[𝕜] F₁ →L[𝕜] F₃))` +to `ContinuousLinearMap.differentiable`. +-/ theorem MDifferentiableWithinAt.clm_precomp {f : M → F₁ →L[𝕜] F₂} {s : Set M} {x : M} (hf : MDifferentiableWithinAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) f s x) : MDifferentiableWithinAt I 𝓘(𝕜, (F₂ →L[𝕜] F₃) →L[𝕜] (F₁ →L[𝕜] F₃)) (fun y ↦ (f y).precomp F₃ : M → (F₂ →L[𝕜] F₃) →L[𝕜] (F₁ →L[𝕜] F₃)) s x := Differentiable.comp_mdifferentiableWithinAt (g := (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip) - (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip.differentiable hf - + (ContinuousLinearMap.differentiable (𝕜 := 𝕜) (F := ((F₂ →L[𝕜] F₃) →L[𝕜] F₁ →L[𝕜] F₃)) + (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip) hf + +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6024 +we needed to add the named arguments `𝕜 := 𝕜` and `F := ((F₂ →L[𝕜] F₃) →L[𝕜] F₁ →L[𝕜] F₃))` +to `ContinuousLinearMap.differentiable`. +-/ nonrec theorem MDifferentiableAt.clm_precomp {f : M → F₁ →L[𝕜] F₂} {x : M} (hf : MDifferentiableAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) f x) : MDifferentiableAt I 𝓘(𝕜, (F₂ →L[𝕜] F₃) →L[𝕜] (F₁ →L[𝕜] F₃)) (fun y ↦ (f y).precomp F₃ : M → (F₂ →L[𝕜] F₃) →L[𝕜] (F₁ →L[𝕜] F₃)) x := Differentiable.comp_mdifferentiableAt (g := (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip) - (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip.differentiable hf + (ContinuousLinearMap.differentiable (𝕜 := 𝕜) (F := ((F₂ →L[𝕜] F₃) →L[𝕜] F₁ →L[𝕜] F₃)) + (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).flip) hf theorem MDifferentiableOn.clm_precomp {f : M → F₁ →L[𝕜] F₂} {s : Set M} (hf : MDifferentiableOn I 𝓘(𝕜, F₁ →L[𝕜] F₂) f s) : @@ -107,21 +121,35 @@ theorem MDifferentiable.clm_precomp (fun y ↦ (f y).precomp F₃ : M → (F₂ →L[𝕜] F₃) →L[𝕜] (F₁ →L[𝕜] F₃)) := fun x ↦ (hf x).clm_precomp +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6024 +we needed to add the named arguments `𝕜 := 𝕜` and `F := ((F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃))` +to `ContinuousLinearMap.differentiable`. +-/ theorem MDifferentiableWithinAt.clm_postcomp {f : M → F₂ →L[𝕜] F₃} {s : Set M} {x : M} (hf : MDifferentiableWithinAt I 𝓘(𝕜, F₂ →L[𝕜] F₃) f s x) : MDifferentiableWithinAt I 𝓘(𝕜, (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) (fun y ↦ (f y).postcomp F₁ : M → (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) s x := Differentiable.comp_mdifferentiableWithinAt (F' := (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) (g := ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃) - (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).differentiable hf - + (ContinuousLinearMap.differentiable (𝕜 := 𝕜) (F := ((F₁ →L[𝕜] F₂) →L[𝕜] F₁ →L[𝕜] F₃)) + (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃)) hf + +#adaptation_note +/-- +After https://github.com/leanprover/lean4/pull/6024 +we needed to add the named arguments `𝕜 := 𝕜` and `F := ((F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃))` +to `ContinuousLinearMap.differentiable`. +-/ theorem MDifferentiableAt.clm_postcomp {f : M → F₂ →L[𝕜] F₃} {x : M} (hf : MDifferentiableAt I 𝓘(𝕜, F₂ →L[𝕜] F₃) f x) : MDifferentiableAt I 𝓘(𝕜, (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) (fun y ↦ (f y).postcomp F₁ : M → (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) x := Differentiable.comp_mdifferentiableAt (F' := (F₁ →L[𝕜] F₂) →L[𝕜] (F₁ →L[𝕜] F₃)) (g := ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃) - (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃).differentiable hf + (ContinuousLinearMap.differentiable (𝕜 := 𝕜) (F := ((F₁ →L[𝕜] F₂) →L[𝕜] F₁ →L[𝕜] F₃)) + (ContinuousLinearMap.compL 𝕜 F₁ F₂ F₃)) hf nonrec theorem MDifferentiableOn.clm_postcomp {f : M → F₂ →L[𝕜] F₃} {s : Set M} (hf : MDifferentiableOn I 𝓘(𝕜, F₂ →L[𝕜] F₃) f s) : @@ -161,8 +189,8 @@ theorem MDifferentiable.clm_comp {g : M → F₁ →L[𝕜] F₃} {f : M → F (hg : MDifferentiable I 𝓘(𝕜, F₁ →L[𝕜] F₃) g) (hf : MDifferentiable I 𝓘(𝕜, F₂ →L[𝕜] F₁) f) : MDifferentiable I 𝓘(𝕜, F₂ →L[𝕜] F₃) fun x => (g x).comp (f x) := fun x => (hg x).clm_comp (hf x) -/-- Applying a linear map to a vector is smooth within a set. Version in vector spaces. For a -version in nontrivial vector bundles, see `MDifferentiableWithinAt.clm_apply_of_inCoordinates`. -/ +/-- Applying a linear map to a vector is differentiable within a set. Version in vector spaces. For +a version in nontrivial vector bundles, see `MDifferentiableWithinAt.clm_apply_of_inCoordinates`. -/ theorem MDifferentiableWithinAt.clm_apply {g : M → F₁ →L[𝕜] F₂} {f : M → F₁} {s : Set M} {x : M} (hg : MDifferentiableWithinAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) g s x) (hf : MDifferentiableWithinAt I 𝓘(𝕜, F₁) f s x) : @@ -173,7 +201,7 @@ theorem MDifferentiableWithinAt.clm_apply {g : M → F₁ →L[𝕜] F₂} {f : exact differentiable_fst.clm_apply differentiable_snd) (hg.prod_mk_space hf) (by simp_rw [mapsTo_univ]) -/-- Applying a linear map to a vector is smooth. Version in vector spaces. For a +/-- Applying a linear map to a vector is differentiable. Version in vector spaces. For a version in nontrivial vector bundles, see `MDifferentiableAt.clm_apply_of_inCoordinates`. -/ theorem MDifferentiableAt.clm_apply {g : M → F₁ →L[𝕜] F₂} {f : M → F₁} {x : M} (hg : MDifferentiableAt I 𝓘(𝕜, F₁ →L[𝕜] F₂) g x) (hf : MDifferentiableAt I 𝓘(𝕜, F₁) f x) : @@ -254,7 +282,7 @@ theorem MDifferentiable.clm_prodMap {g : M → F₁ →L[𝕜] F₃} {f : M → MDifferentiable I 𝓘(𝕜, F₁ × F₂ →L[𝕜] F₃ × F₄) fun x => (g x).prodMap (f x) := fun x => (hg x).clm_prodMap (hf x) -/-! ### Smoothness of scalar multiplication -/ +/-! ### Differentiability of scalar multiplication -/ variable {V : Type*} [NormedAddCommGroup V] [NormedSpace 𝕜 V] diff --git a/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean index 7afe6dc78bd73..2c048b112606f 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/Tangent.lean @@ -6,6 +6,7 @@ Authors: Sébastien Gouëzel, Floris van Doorn import Mathlib.Geometry.Manifold.MFDeriv.Atlas import Mathlib.Geometry.Manifold.MFDeriv.UniqueDifferential import Mathlib.Geometry.Manifold.VectorBundle.Tangent +import Mathlib.Geometry.Manifold.Diffeomorph /-! # Derivatives of maps in the tangent bundle @@ -62,7 +63,7 @@ lemma mfderiv_chartAt_eq_tangentCoordChange {x y : M} (hsrc : x ∈ (chartAt H y the basis also has unique differential. -/ theorem UniqueMDiffOn.tangentBundle_proj_preimage {s : Set M} (hs : UniqueMDiffOn I s) : UniqueMDiffOn I.tangent (π E (TangentSpace I) ⁻¹' s) := - hs.smooth_bundle_preimage _ + hs.bundle_preimage _ /-- To write a linear map between tangent spaces in coordinates amounts to precomposing and postcomposing it with derivatives of extended charts. @@ -87,3 +88,13 @@ lemma inTangentCoordinates_eq_mfderiv_comp · apply mdifferentiableWithinAt_extChartAt_symm apply (extChartAt I (f x₀)).map_source simpa using hx + +open Bundle +variable (I) in +/-- The canonical identification between the tangent bundle to the model space and the product, +as a diffeomorphism -/ +def tangentBundleModelSpaceDiffeomorph (n : ℕ∞) : + TangentBundle I H ≃ₘ^n⟮I.tangent, I.prod 𝓘(𝕜, E)⟯ ModelProd H E where + __ := TotalSpace.toProd H E + contMDiff_toFun := contMDiff_tangentBundleModelSpaceHomeomorph + contMDiff_invFun := contMDiff_tangentBundleModelSpaceHomeomorph_symm diff --git a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean index e090b101ab9e7..2382f7093e3f8 100644 --- a/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean +++ b/Mathlib/Geometry/Manifold/MFDeriv/UniqueDifferential.lean @@ -85,16 +85,29 @@ theorem UniqueMDiffOn.uniqueMDiffOn_preimage (hs : UniqueMDiffOn I s) {e : Parti variable [SmoothManifoldWithCorners I M] in /-- If a set in a manifold has the unique derivative property, then its pullback by any extended chart, in the vector space, also has the unique derivative property. -/ -theorem UniqueMDiffOn.uniqueDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) : - UniqueDiffOn 𝕜 ((extChartAt I x).target ∩ (extChartAt I x).symm ⁻¹' s) := by +theorem UniqueMDiffOn.uniqueMDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) : + UniqueMDiffOn 𝓘(𝕜, E) ((extChartAt I x).target ∩ (extChartAt I x).symm ⁻¹' s) := by -- this is just a reformulation of `UniqueMDiffOn.uniqueMDiffOn_preimage`, using as `e` -- the local chart at `x`. - apply UniqueMDiffOn.uniqueDiffOn rw [← PartialEquiv.image_source_inter_eq', inter_comm, extChartAt_source] exact (hs.inter (chartAt H x).open_source).image_denseRange' (fun y hy ↦ hasMFDerivWithinAt_extChartAt hy.2) fun y hy ↦ ((mdifferentiable_chart _).mfderiv_surjective hy.2).denseRange +variable [SmoothManifoldWithCorners I M] in +/-- If a set in a manifold has the unique derivative property, then its pullback by any extended +chart, in the vector space, also has the unique derivative property. -/ +theorem UniqueMDiffOn.uniqueDiffOn_target_inter (hs : UniqueMDiffOn I s) (x : M) : + UniqueDiffOn 𝕜 ((extChartAt I x).target ∩ (extChartAt I x).symm ⁻¹' s) := + (hs.uniqueMDiffOn_target_inter x).uniqueDiffOn + +variable [SmoothManifoldWithCorners I M] in +theorem UniqueMDiffOn.uniqueDiffWithinAt_range_inter (hs : UniqueMDiffOn I s) (x : M) (y : E) + (hy : y ∈ (extChartAt I x).target ∩ (extChartAt I x).symm ⁻¹' s) : + UniqueDiffWithinAt 𝕜 (range I ∩ (extChartAt I x).symm ⁻¹' s) y := by + apply (hs.uniqueDiffOn_target_inter x y hy).mono + apply inter_subset_inter_left _ (extChartAt_target_subset_range x) + variable [SmoothManifoldWithCorners I M] in /-- When considering functions between manifolds, this statement shows up often. It entails the unique differential of the pullback in extended charts of the set where the function can @@ -115,36 +128,78 @@ end open Bundle variable {F : Type*} [NormedAddCommGroup F] [NormedSpace 𝕜 F] {Z : M → Type*} - [TopologicalSpace (TotalSpace F Z)] [∀ b, TopologicalSpace (Z b)] [∀ b, AddCommMonoid (Z b)] - [∀ b, Module 𝕜 (Z b)] [FiberBundle F Z] [VectorBundle 𝕜 F Z] [SmoothVectorBundle F Z I] + [TopologicalSpace (TotalSpace F Z)] [∀ b, TopologicalSpace (Z b)] [FiberBundle F Z] -theorem Trivialization.mdifferentiable (e : Trivialization F (π F Z)) [MemTrivializationAtlas e] : - e.toPartialHomeomorph.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := - ⟨e.contMDiffOn.mdifferentiableOn le_top, e.contMDiffOn_symm.mdifferentiableOn le_top⟩ - -theorem UniqueMDiffWithinAt.smooth_bundle_preimage {p : TotalSpace F Z} +private lemma UniqueMDiffWithinAt.bundle_preimage_aux {p : TotalSpace F Z} + (hs : UniqueMDiffWithinAt I s p.proj) (h's : s ⊆ (trivializationAt F Z p.proj).baseSet) : + UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) p := by + suffices ((extChartAt I p.proj).symm ⁻¹' s ∩ range I) ×ˢ univ ⊆ + (extChartAt (I.prod 𝓘(𝕜, F)) p).symm ⁻¹' (TotalSpace.proj ⁻¹' s) ∩ range (I.prod 𝓘(𝕜, F)) by + let w := (extChartAt (I.prod 𝓘(𝕜, F)) p p).2 + have A : extChartAt (I.prod 𝓘(𝕜, F)) p p = (extChartAt I p.1 p.1, w) := by + ext + · simp [FiberBundle.chartedSpace_chartAt] + · rfl + simp only [UniqueMDiffWithinAt, A] at hs ⊢ + exact (hs.prod (uniqueDiffWithinAt_univ (x := w))).mono this + rcases p with ⟨x, v⟩ + dsimp + rintro ⟨z, w⟩ ⟨hz, -⟩ + simp only [ModelWithCorners.target_eq, mem_inter_iff, mem_preimage, Function.comp_apply, + mem_range] at hz + simp only [FiberBundle.chartedSpace_chartAt, PartialHomeomorph.coe_trans_symm, mem_inter_iff, + mem_preimage, Function.comp_apply, mem_range] + constructor + · rw [PartialEquiv.prod_symm, PartialEquiv.refl_symm, PartialEquiv.prod_coe, + ModelWithCorners.toPartialEquiv_coe_symm, PartialEquiv.refl_coe, + PartialHomeomorph.prod_symm, PartialHomeomorph.refl_symm, PartialHomeomorph.prod_apply, + PartialHomeomorph.refl_apply] + convert hz.1 + apply Trivialization.proj_symm_apply' + exact h's hz.1 + · rcases hz.2 with ⟨u, rfl⟩ + exact ⟨(u, w), rfl⟩ + +/-- In a fiber bundle, the preimage under the projection of a set with unique differentials +in the base has unique differentials in the bundle. -/ +theorem UniqueMDiffWithinAt.bundle_preimage {p : TotalSpace F Z} (hs : UniqueMDiffWithinAt I s p.proj) : UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) p := by - set e := trivializationAt F Z p.proj - have hp : p ∈ e.source := FiberBundle.mem_trivializationAt_proj_source - have : UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) (s ×ˢ univ) (e p) := by - rw [← Prod.mk.eta (p := e p), FiberBundle.trivializationAt_proj_fst] - exact hs.prod (uniqueMDiffWithinAt_univ _) - rw [← e.left_inv hp] - refine (this.preimage_partialHomeomorph e.mdifferentiable.symm (e.map_source hp)).mono ?_ - rintro y ⟨hy, hys, -⟩ - rwa [PartialHomeomorph.symm_symm, e.coe_coe, e.coe_fst hy] at hys + suffices UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) + (π F Z ⁻¹' (s ∩ (trivializationAt F Z p.proj).baseSet)) p from this.mono (by simp) + apply UniqueMDiffWithinAt.bundle_preimage_aux (hs.inter _) inter_subset_right + exact IsOpen.mem_nhds (trivializationAt F Z p.proj).open_baseSet + (FiberBundle.mem_baseSet_trivializationAt' p.proj) + +@[deprecated (since := "2024-12-02")] +alias UniqueMDiffWithinAt.smooth_bundle_preimage := UniqueMDiffWithinAt.bundle_preimage variable (Z) -theorem UniqueMDiffWithinAt.smooth_bundle_preimage' {b : M} (hs : UniqueMDiffWithinAt I s b) +/-- In a fiber bundle, the preimage under the projection of a set with unique differentials +in the base has unique differentials in the bundle. Version with a point `⟨b, x⟩`. -/ +theorem UniqueMDiffWithinAt.bundle_preimage' {b : M} (hs : UniqueMDiffWithinAt I s b) (x : Z b) : UniqueMDiffWithinAt (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) ⟨b, x⟩ := - hs.smooth_bundle_preimage (p := ⟨b, x⟩) + hs.bundle_preimage (p := ⟨b, x⟩) + +@[deprecated (since := "2024-12-02")] +alias UniqueMDiffWithinAt.smooth_bundle_preimage' := UniqueMDiffWithinAt.bundle_preimage' -/-- In a smooth fiber bundle, the preimage under the projection of a set with -unique differential in the basis also has unique differential. -/ -theorem UniqueMDiffOn.smooth_bundle_preimage (hs : UniqueMDiffOn I s) : +/-- In a fiber bundle, the preimage under the projection of a set with unique differentials +in the base has unique differentials in the bundle. -/ +theorem UniqueMDiffOn.bundle_preimage (hs : UniqueMDiffOn I s) : UniqueMDiffOn (I.prod 𝓘(𝕜, F)) (π F Z ⁻¹' s) := fun _p hp ↦ - (hs _ hp).smooth_bundle_preimage + (hs _ hp).bundle_preimage + +@[deprecated (since := "2024-12-02")] +alias UniqueMDiffOn.smooth_bundle_preimage := UniqueMDiffOn.bundle_preimage + +/- TODO: move me to `Mathlib.Geometry.Manifold.VectorBundle.MDifferentiable` once #19636 is in. -/ +variable [∀ b, AddCommMonoid (Z b)] [∀ b, Module 𝕜 (Z b)] [VectorBundle 𝕜 F Z] + +theorem Trivialization.mdifferentiable [SmoothVectorBundle F Z I] + (e : Trivialization F (π F Z)) [MemTrivializationAtlas e] : + e.MDifferentiable (I.prod 𝓘(𝕜, F)) (I.prod 𝓘(𝕜, F)) := + ⟨e.contMDiffOn.mdifferentiableOn le_top, e.contMDiffOn_symm.mdifferentiableOn le_top⟩ end UniqueMDiff diff --git a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean index 5c91ede6dc259..787dce0f8a583 100644 --- a/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean +++ b/Mathlib/Geometry/Manifold/Sheaf/LocallyRingedSpace.lean @@ -35,7 +35,7 @@ universe u Later, replace with `open scoped ContDiff`. -/ local notation "∞" => (⊤ : ℕ∞) -variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] [CompleteSpace 𝕜] +variable {𝕜 : Type u} [NontriviallyNormedField 𝕜] {EM : Type*} [NormedAddCommGroup EM] [NormedSpace 𝕜 EM] {HM : Type*} [TopologicalSpace HM] (IM : ModelWithCorners 𝕜 EM HM) {M : Type u} [TopologicalSpace M] [ChartedSpace HM M] diff --git a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean index 7511ccb7ad482..9fcbaff7d4fac 100644 --- a/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean +++ b/Mathlib/Geometry/Manifold/SmoothManifoldWithCorners.lean @@ -48,12 +48,14 @@ but add these assumptions later as needed. (Quite a few results still do not req `extChartAt I x` is the canonical such partial equiv around `x`. As specific examples of models with corners, we define (in `Geometry.Manifold.Instances.Real`) -* `modelWithCornersSelf ℝ (EuclideanSpace ℝ (Fin n))` for the model space used to define +* `modelWithCornersEuclideanHalfSpace n : + ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)` for the model space `n`-dimensional real manifolds without boundary (with notation `𝓡 n` in the locale `Manifold`) * `ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanHalfSpace n)` for the model space used to define `n`-dimensional real manifolds with boundary (with notation `𝓡∂ n` in the locale `Manifold`) -* `ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanQuadrant n)` for the model space used +* `modelWithCornersEuclideanQuadrant n : + ModelWithCorners ℝ (EuclideanSpace ℝ (Fin n)) (EuclideanQuadrant n)` for the model space used to define `n`-dimensional real manifolds with corners With these definitions at hand, to invoke an `n`-dimensional real manifold without boundary, @@ -369,7 +371,7 @@ protected theorem secondCountableTopology [SecondCountableTopology E] (I : Model I.isClosedEmbedding.isEmbedding.secondCountableTopology include I in -/-- Every smooth manifold is a Fréchet space (T1 space) -- regardless of whether it is +/-- Every manifold is a Fréchet space (T1 space) -- regardless of whether it is Hausdorff. -/ protected theorem t1Space (M : Type*) [TopologicalSpace M] [ChartedSpace H M] : T1Space M := by have : T2Space H := I.isClosedEmbedding.toIsEmbedding.t2Space diff --git a/Mathlib/Geometry/Manifold/VectorBundle/MDifferentiable.lean b/Mathlib/Geometry/Manifold/VectorBundle/MDifferentiable.lean new file mode 100644 index 0000000000000..3f9eae5d70e38 --- /dev/null +++ b/Mathlib/Geometry/Manifold/VectorBundle/MDifferentiable.lean @@ -0,0 +1,148 @@ +/- +Copyright (c) 2024 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastien Gouëzel +-/ +import Mathlib.Geometry.Manifold.VectorBundle.Basic +import Mathlib.Geometry.Manifold.MFDeriv.NormedSpace +import Mathlib.Geometry.Manifold.MFDeriv.SpecificFunctions + + +/-! +# Differentiability of functions in vector bundles + +-/ + +open Bundle Set PartialHomeomorph ContinuousLinearMap Pretrivialization Filter + +open scoped Manifold Bundle Topology + +section + + +variable {𝕜 B B' F M : Type*} {E : B → Type*} + +variable [NontriviallyNormedField 𝕜] [NormedAddCommGroup F] [NormedSpace 𝕜 F] + [TopologicalSpace (TotalSpace F E)] [∀ x, TopologicalSpace (E x)] {EB : Type*} + [NormedAddCommGroup EB] [NormedSpace 𝕜 EB] {HB : Type*} [TopologicalSpace HB] + (IB : ModelWithCorners 𝕜 EB HB) (E' : B → Type*) [∀ x, Zero (E' x)] {EM : Type*} + [NormedAddCommGroup EM] [NormedSpace 𝕜 EM] {HM : Type*} [TopologicalSpace HM] + {IM : ModelWithCorners 𝕜 EM HM} [TopologicalSpace M] [ChartedSpace HM M] + {n : ℕ∞} + + +variable [TopologicalSpace B] [ChartedSpace HB B] [FiberBundle F E] + +/-- Characterization of differentiable functions into a smooth vector bundle. -/ +theorem mdifferentiableWithinAt_totalSpace (f : M → TotalSpace F E) {s : Set M} {x₀ : M} : + MDifferentiableWithinAt IM (IB.prod 𝓘(𝕜, F)) f s x₀ ↔ + MDifferentiableWithinAt IM IB (fun x => (f x).proj) s x₀ ∧ + MDifferentiableWithinAt IM 𝓘(𝕜, F) + (fun x ↦ (trivializationAt F E (f x₀).proj (f x)).2) s x₀ := by + simp (config := { singlePass := true }) only [mdifferentiableWithinAt_iff_target] + rw [and_and_and_comm, ← FiberBundle.continuousWithinAt_totalSpace, and_congr_right_iff] + intro hf + simp_rw [modelWithCornersSelf_prod, FiberBundle.extChartAt, Function.comp_def, + PartialEquiv.trans_apply, PartialEquiv.prod_coe, PartialEquiv.refl_coe, + extChartAt_self_apply, modelWithCornersSelf_coe, Function.id_def, ← chartedSpaceSelf_prod] + refine (mdifferentiableWithinAt_prod_iff _).trans (and_congr ?_ Iff.rfl) + have h1 : (fun x => (f x).proj) ⁻¹' (trivializationAt F E (f x₀).proj).baseSet ∈ 𝓝[s] x₀ := + ((FiberBundle.continuous_proj F E).continuousWithinAt.comp hf (mapsTo_image f s)) + ((Trivialization.open_baseSet _).mem_nhds (mem_baseSet_trivializationAt F E _)) + refine EventuallyEq.mdifferentiableWithinAt_iff (eventually_of_mem h1 fun x hx => ?_) ?_ + · simp_rw [Function.comp, PartialHomeomorph.coe_coe, Trivialization.coe_coe] + rw [Trivialization.coe_fst'] + exact hx + · simp only [mfld_simps] + +end + + +section + +/- Declare two manifolds `B₁` and `B₂` (with models `IB₁ : HB₁ → EB₁` and `IB₂ : HB₂ → EB₂`), +and two vector bundles `E₁` and `E₂` respectively over `B₁` and `B₂` (with model fibers +`F₁` and `F₂`). + +Also a third manifold `M`, which will be the source of all our maps. +-/ +variable {𝕜 F₁ F₂ B₁ B₂ M : Type*} {E₁ : B₁ → Type*} {E₂ : B₂ → Type*} [NontriviallyNormedField 𝕜] + [∀ x, AddCommGroup (E₁ x)] [∀ x, Module 𝕜 (E₁ x)] [NormedAddCommGroup F₁] [NormedSpace 𝕜 F₁] + [TopologicalSpace (TotalSpace F₁ E₁)] [∀ x, TopologicalSpace (E₁ x)] [∀ x, AddCommGroup (E₂ x)] + [∀ x, Module 𝕜 (E₂ x)] [NormedAddCommGroup F₂] [NormedSpace 𝕜 F₂] + [TopologicalSpace (TotalSpace F₂ E₂)] [∀ x, TopologicalSpace (E₂ x)] + {EB₁ : Type*} + [NormedAddCommGroup EB₁] [NormedSpace 𝕜 EB₁] {HB₁ : Type*} [TopologicalSpace HB₁] + {IB₁ : ModelWithCorners 𝕜 EB₁ HB₁} [TopologicalSpace B₁] [ChartedSpace HB₁ B₁] + {EB₂ : Type*} + [NormedAddCommGroup EB₂] [NormedSpace 𝕜 EB₂] {HB₂ : Type*} [TopologicalSpace HB₂] + {IB₂ : ModelWithCorners 𝕜 EB₂ HB₂} [TopologicalSpace B₂] [ChartedSpace HB₂ B₂] + {EM : Type*} + [NormedAddCommGroup EM] [NormedSpace 𝕜 EM] {HM : Type*} [TopologicalSpace HM] + {IM : ModelWithCorners 𝕜 EM HM} [TopologicalSpace M] [ChartedSpace HM M] + {n : ℕ∞} [FiberBundle F₁ E₁] [VectorBundle 𝕜 F₁ E₁] + [FiberBundle F₂ E₂] [VectorBundle 𝕜 F₂ E₂] + {b₁ : M → B₁} {b₂ : M → B₂} {m₀ : M} + {ϕ : Π (m : M), E₁ (b₁ m) →L[𝕜] E₂ (b₂ m)} {v : Π (m : M), E₁ (b₁ m)} {s : Set M} + +/-- Consider a smooth map `v : M → E₁` to a vector bundle, over a basemap `b₁ : M → B₁`, and +another basemap `b₂ : M → B₂`. Given linear maps `ϕ m : E₁ (b₁ m) → E₂ (b₂ m)` depending smoothly +on `m`, one can apply `ϕ m` to `g m`, and the resulting map is smooth. + +Note that the smoothness of `ϕ` can not be always be stated as smoothness of a map into a manifold, +as the pullback bundles `b₁ *ᵖ E₁` and `b₂ *ᵖ E₂` only make sense when `b₁` and `b₂` are globally +smooth, but we want to apply this lemma with only local information. Therefore, we formulate it +using smoothness of `ϕ` read in coordinates. + +Version for `MDifferentiableWithinAt`. We also give a version for `MDifferentiableAt`, but no +version for `MDifferentiableOn` or `MDifferentiable` as our assumption, written in coordinates, +only makes sense around a point. + -/ +lemma MDifferentiableWithinAt.clm_apply_of_inCoordinates + (hϕ : MDifferentiableWithinAt IM 𝓘(𝕜, F₁ →L[𝕜] F₂) + (fun m ↦ inCoordinates F₁ E₁ F₂ E₂ (b₁ m₀) (b₁ m) (b₂ m₀) (b₂ m) (ϕ m)) s m₀) + (hv : MDifferentiableWithinAt IM (IB₁.prod 𝓘(𝕜, F₁)) (fun m ↦ (v m : TotalSpace F₁ E₁)) s m₀) + (hb₂ : MDifferentiableWithinAt IM IB₂ b₂ s m₀) : + MDifferentiableWithinAt IM (IB₂.prod 𝓘(𝕜, F₂)) + (fun m ↦ (ϕ m (v m) : TotalSpace F₂ E₂)) s m₀ := by + rw [mdifferentiableWithinAt_totalSpace] at hv ⊢ + refine ⟨hb₂, ?_⟩ + apply (MDifferentiableWithinAt.clm_apply hϕ hv.2).congr_of_eventuallyEq_insert + have A : ∀ᶠ m in 𝓝[insert m₀ s] m₀, b₁ m ∈ (trivializationAt F₁ E₁ (b₁ m₀)).baseSet := by + apply hv.1.insert.continuousWithinAt + apply (trivializationAt F₁ E₁ (b₁ m₀)).open_baseSet.mem_nhds + exact FiberBundle.mem_baseSet_trivializationAt' (b₁ m₀) + have A' : ∀ᶠ m in 𝓝[insert m₀ s] m₀, b₂ m ∈ (trivializationAt F₂ E₂ (b₂ m₀)).baseSet := by + apply hb₂.insert.continuousWithinAt + apply (trivializationAt F₂ E₂ (b₂ m₀)).open_baseSet.mem_nhds + exact FiberBundle.mem_baseSet_trivializationAt' (b₂ m₀) + filter_upwards [A, A'] with m hm h'm + rw [inCoordinates_eq hm h'm] + simp only [coe_comp', ContinuousLinearEquiv.coe_coe, Trivialization.continuousLinearEquivAt_apply, + Trivialization.continuousLinearEquivAt_symm_apply, Function.comp_apply] + congr + rw [Trivialization.symm_apply_apply_mk (trivializationAt F₁ E₁ (b₁ m₀)) hm (v m)] + +/-- Consider a smooth map `v : M → E₁` to a vector bundle, over a basemap `b₁ : M → B₁`, and +another basemap `b₂ : M → B₂`. Given linear maps `ϕ m : E₁ (b₁ m) → E₂ (b₂ m)` depending smoothly +on `m`, one can apply `ϕ m` to `g m`, and the resulting map is smooth. + +Note that the smoothness of `ϕ` can not be always be stated as smoothness of a map into a manifold, +as the pullback bundles `b₁ *ᵖ E₁` and `b₂ *ᵖ E₂` only make sense when `b₁` and `b₂` are globally +smooth, but we want to apply this lemma with only local information. Therefore, we formulate it +using smoothness of `ϕ` read in coordinates. + +Version for `MDifferentiableAt`. We also give a version for `MDifferentiableWithinAt`, +but no version for `MDifferentiableOn` or `MDifferentiable` as our assumption, written +in coordinates, only makes sense around a point. + -/ +lemma MDifferentiableAt.clm_apply_of_inCoordinates + (hϕ : MDifferentiableAt IM 𝓘(𝕜, F₁ →L[𝕜] F₂) + (fun m ↦ inCoordinates F₁ E₁ F₂ E₂ (b₁ m₀) (b₁ m) (b₂ m₀) (b₂ m) (ϕ m)) m₀) + (hv : MDifferentiableAt IM (IB₁.prod 𝓘(𝕜, F₁)) (fun m ↦ (v m : TotalSpace F₁ E₁)) m₀) + (hb₂ : MDifferentiableAt IM IB₂ b₂ m₀) : + MDifferentiableAt IM (IB₂.prod 𝓘(𝕜, F₂)) (fun m ↦ (ϕ m (v m) : TotalSpace F₂ E₂)) m₀ := by + rw [← mdifferentiableWithinAt_univ] at hϕ hv hb₂ ⊢ + exact MDifferentiableWithinAt.clm_apply_of_inCoordinates hϕ hv hb₂ + +end diff --git a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean index 5931fefe4f64b..05b06edfad0ea 100644 --- a/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean +++ b/Mathlib/Geometry/Manifold/VectorBundle/Tangent.lean @@ -300,6 +300,14 @@ end TangentBundleInstances /-! ## The tangent bundle to the model space -/ +@[simp, mfld_simps] +theorem trivializationAt_model_space_apply (p : TangentBundle I H) (x : H) : + trivializationAt E (TangentSpace I) x p = (p.1, p.2) := by + simp [TangentBundle.trivializationAt_apply] + have : fderivWithin 𝕜 (↑I ∘ ↑I.symm) (range I) (I p.proj) = + fderivWithin 𝕜 id (range I) (I p.proj) := + fderivWithin_congr' (fun y hy ↦ by simp [hy]) (mem_range_self p.proj) + simp [this, fderivWithin_id (ModelWithCorners.uniqueDiffWithinAt_image I)] /-- In the tangent bundle to the model space, the charts are just the canonical identification between a product type and a sigma type, a.k.a. `TotalSpace.toProd`. -/ @@ -336,7 +344,7 @@ theorem tangentBundleCore_coordChange_model_space (x x' z : H) : variable (I) in /-- The canonical identification between the tangent bundle to the model space and the product, -as a homeomorphism -/ +as a homeomorphism. For the diffeomorphism version, see `tangentBundleModelSpaceDiffeomorph`. -/ def tangentBundleModelSpaceHomeomorph : TangentBundle I H ≃ₜ ModelProd H E := { TotalSpace.toProd H E with continuous_toFun := by @@ -366,11 +374,83 @@ theorem tangentBundleModelSpaceHomeomorph_coe_symm : (TotalSpace.toProd H E).symm := rfl +theorem contMDiff_tangentBundleModelSpaceHomeomorph {n : ℕ∞} : + ContMDiff I.tangent (I.prod 𝓘(𝕜, E)) n + (tangentBundleModelSpaceHomeomorph I : TangentBundle I H → ModelProd H E) := by + apply contMDiff_iff.2 ⟨Homeomorph.continuous _, fun x y ↦ ?_⟩ + apply contDiffOn_id.congr + simp only [mfld_simps, mem_range, TotalSpace.toProd, Equiv.coe_fn_symm_mk, forall_exists_index, + Prod.forall, Prod.mk.injEq] + rintro a b x rfl + simp [PartialEquiv.prod] + +theorem contMDiff_tangentBundleModelSpaceHomeomorph_symm {n : ℕ∞} : + ContMDiff (I.prod 𝓘(𝕜, E)) I.tangent n + ((tangentBundleModelSpaceHomeomorph I).symm : ModelProd H E → TangentBundle I H) := by + apply contMDiff_iff.2 ⟨Homeomorph.continuous _, fun x y ↦ ?_⟩ + apply contDiffOn_id.congr + simp only [mfld_simps, mem_range, TotalSpace.toProd, Equiv.coe_fn_symm_mk, forall_exists_index, + Prod.forall, Prod.mk.injEq] + rintro a b x rfl + simp [PartialEquiv.prod] + exact ⟨rfl, rfl⟩ + +variable (H I) in +/-- In the tangent bundle to the model space, the second projection is smooth. -/ +lemma contMDiff_snd_tangentBundle_modelSpace {n : ℕ∞} : + ContMDiff I.tangent 𝓘(𝕜, E) n (fun (p : TangentBundle I H) ↦ p.2) := by + change ContMDiff I.tangent 𝓘(𝕜, E) n + ((id Prod.snd : ModelProd H E → E) ∘ (tangentBundleModelSpaceHomeomorph I)) + apply ContMDiff.comp (I' := I.prod 𝓘(𝕜, E)) + · convert contMDiff_snd + rw [chartedSpaceSelf_prod] + rfl + · exact contMDiff_tangentBundleModelSpaceHomeomorph + +/-- A vector field on a vector space is smooth in the manifold sense iff it is smoooth in the vector +space sense-/ +lemma contMDiffWithinAt_vectorSpace_iff_contDiffWithinAt + {V : Π (x : E), TangentSpace 𝓘(𝕜, E) x} {n : ℕ∞} {s : Set E} {x : E} : + ContMDiffWithinAt 𝓘(𝕜, E) 𝓘(𝕜, E).tangent n (fun x ↦ (V x : TangentBundle 𝓘(𝕜, E) E)) s x ↔ + ContDiffWithinAt 𝕜 n V s x := by + refine ⟨fun h ↦ ?_, fun h ↦ ?_⟩ + · exact ContMDiffWithinAt.contDiffWithinAt <| + (contMDiff_snd_tangentBundle_modelSpace E 𝓘(𝕜, E)).contMDiffAt.comp_contMDiffWithinAt _ h + · apply (Bundle.contMDiffWithinAt_totalSpace _).2 + refine ⟨contMDiffWithinAt_id, ?_⟩ + convert h.contMDiffWithinAt with y + simp + +/-- A vector field on a vector space is smooth in the manifold sense iff it is smoooth in the vector +space sense-/ +lemma contMDiffAt_vectorSpace_iff_contDiffAt + {V : Π (x : E), TangentSpace 𝓘(𝕜, E) x} {n : ℕ∞} {x : E} : + ContMDiffAt 𝓘(𝕜, E) 𝓘(𝕜, E).tangent n (fun x ↦ (V x : TangentBundle 𝓘(𝕜, E) E)) x ↔ + ContDiffAt 𝕜 n V x := by + simp only [← contMDiffWithinAt_univ, ← contDiffWithinAt_univ, + contMDiffWithinAt_vectorSpace_iff_contDiffWithinAt] + +/-- A vector field on a vector space is smooth in the manifold sense iff it is smoooth in the vector +space sense-/ +lemma contMDiffOn_vectorSpace_iff_contDiffOn + {V : Π (x : E), TangentSpace 𝓘(𝕜, E) x} {n : ℕ∞} {s : Set E} : + ContMDiffOn 𝓘(𝕜, E) 𝓘(𝕜, E).tangent n (fun x ↦ (V x : TangentBundle 𝓘(𝕜, E) E)) s ↔ + ContDiffOn 𝕜 n V s := by + simp only [ContMDiffOn, ContDiffOn, contMDiffWithinAt_vectorSpace_iff_contDiffWithinAt ] + +/-- A vector field on a vector space is smooth in the manifold sense iff it is smoooth in the vector +space sense-/ +lemma contMDiff_vectorSpace_iff_contDiff + {V : Π (x : E), TangentSpace 𝓘(𝕜, E) x} {n : ℕ∞} : + ContMDiff 𝓘(𝕜, E) 𝓘(𝕜, E).tangent n (fun x ↦ (V x : TangentBundle 𝓘(𝕜, E) E)) ↔ + ContDiff 𝕜 n V := by + simp only [← contMDiffOn_univ, ← contDiffOn_univ, contMDiffOn_vectorSpace_iff_contDiffOn] + section inTangentCoordinates variable {N : Type*} -/-- The map `in_coordinates` for the tangent bundle is trivial on the model spaces -/ +/-- The map `inCoordinates` for the tangent bundle is trivial on the model spaces -/ theorem inCoordinates_tangent_bundle_core_model_space (x₀ x : H) (y₀ y : H') (ϕ : E →L[𝕜] E') : inCoordinates E (TangentSpace I) E' (TangentSpace I') x₀ x y₀ y ϕ = ϕ := by erw [VectorBundleCore.inCoordinates_eq] <;> try trivial @@ -397,6 +477,10 @@ theorem inTangentCoordinates_model_space (f : N → H) (g : N → H') (ϕ : N simp (config := { unfoldPartialApp := true }) only [inTangentCoordinates, inCoordinates_tangent_bundle_core_model_space] +/-- To write a linear map between tangent spaces in coordinates amounts to precomposing and +postcomposing it with suitable coordinate changes. For a concrete version expressing the +change of coordinates as derivatives of extended charts, +see `inTangentCoordinates_eq_mfderiv_comp`. -/ theorem inTangentCoordinates_eq (f : N → M) (g : N → M') (ϕ : N → E →L[𝕜] E') {x₀ x : N} (hx : f x ∈ (chartAt H (f x₀)).source) (hy : g x ∈ (chartAt H' (g x₀)).source) : inTangentCoordinates I I' f g ϕ x₀ x = diff --git a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean index 5c87be9ceb0bc..df614fe6a7795 100644 --- a/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean +++ b/Mathlib/Geometry/RingedSpace/PresheafedSpace/Gluing.lean @@ -92,7 +92,7 @@ that the `U i`'s are open subspaces of the glued space. -/ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/5171): this linter isn't ported yet. -- @[nolint has_nonempty_instance] -structure GlueData extends GlueData (PresheafedSpace.{u, v, v} C) where +structure GlueData extends CategoryTheory.GlueData (PresheafedSpace.{u, v, v} C) where f_open : ∀ i j, IsOpenImmersion (f i j) attribute [instance] GlueData.f_open diff --git a/Mathlib/GroupTheory/Congruence/Basic.lean b/Mathlib/GroupTheory/Congruence/Basic.lean index 259eef9b6e583..5f5f5d7432161 100644 --- a/Mathlib/GroupTheory/Congruence/Basic.lean +++ b/Mathlib/GroupTheory/Congruence/Basic.lean @@ -256,7 +256,7 @@ lemma comapQuotientEquivOfSurj_symm_mk (c : Con M) {f : N →* M} (hf) (x : N) : MulEquiv function"] lemma comapQuotientEquivOfSurj_symm_mk' (c : Con M) (f : N ≃* M) (x : N) : ((@MulEquiv.symm (Con.Quotient (comap ⇑f _ c)) _ _ _ - (comapQuotientEquivOfSurj c f f.surjective)) ⟦f x⟧) = ↑x := + (comapQuotientEquivOfSurj c (f : N →* M) f.surjective)) ⟦f x⟧) = ↑x := (MulEquiv.symm_apply_eq (@comapQuotientEquivOfSurj M N _ _ c f _)).mpr rfl /-- The **second isomorphism theorem for monoids**. -/ diff --git a/Mathlib/GroupTheory/Congruence/Defs.lean b/Mathlib/GroupTheory/Congruence/Defs.lean index 0026330ad4b73..9ecaf70c760a9 100644 --- a/Mathlib/GroupTheory/Congruence/Defs.lean +++ b/Mathlib/GroupTheory/Congruence/Defs.lean @@ -281,7 +281,7 @@ protected theorem eq {a b : M} : (a : c.Quotient) = (b : c.Quotient) ↔ c a b : @[to_additive "The addition induced on the quotient by an additive congruence relation on a type with an addition."] instance hasMul : Mul c.Quotient := - ⟨Quotient.map₂' (· * ·) fun _ _ h1 _ _ h2 => c.mul h1 h2⟩ + ⟨Quotient.map₂ (· * ·) fun _ _ h1 _ _ h2 => c.mul h1 h2⟩ /-- The kernel of the quotient map induced by a congruence relation `c` equals `c`. -/ @[to_additive (attr := simp) "The kernel of the quotient map induced by an additive congruence @@ -739,7 +739,7 @@ instance hasInv : Inv c.Quotient := @[to_additive "The subtraction induced on the quotient by an additive congruence relation on a type with a subtraction."] instance hasDiv : Div c.Quotient := - ⟨(Quotient.map₂' (· / ·)) fun _ _ h₁ _ _ h₂ => c.div h₁ h₂⟩ + ⟨(Quotient.map₂ (· / ·)) fun _ _ h₁ _ _ h₂ => c.div h₁ h₂⟩ /-- The integer scaling induced on the quotient by a congruence relation on a type with a subtraction. -/ diff --git a/Mathlib/GroupTheory/Coxeter/Basic.lean b/Mathlib/GroupTheory/Coxeter/Basic.lean index 1ab0f3e0bef58..c33678eadac13 100644 --- a/Mathlib/GroupTheory/Coxeter/Basic.lean +++ b/Mathlib/GroupTheory/Coxeter/Basic.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2024 Newell Jensen. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Newell Jensen, Mitchell Lee +Authors: Newell Jensen, Mitchell Lee, Óscar Álvarez -/ import Mathlib.Algebra.Group.Subgroup.Pointwise import Mathlib.Algebra.Ring.Int.Parity @@ -411,6 +411,81 @@ theorem length_alternatingWord (i i' : B) (m : ℕ) : · dsimp [alternatingWord] · simpa [alternatingWord] using ih i' i +lemma getElem_alternatingWord (i j : B) (p k : ℕ) (hk : k < p) : + (alternatingWord i j p)[k]'(by simp; exact hk) = (if Even (p + k) then i else j) := by + revert k + induction p with + | zero => + intro k hk + simp only [not_lt_zero'] at hk + | succ n h => + intro k hk + simp_rw [alternatingWord_succ' i j n] + match k with + | 0 => + by_cases h2 : Even n + · simp only [h2, ↓reduceIte, getElem_cons_zero, add_zero, + (by simp [Even.add_one, h2] : ¬Even (n + 1))] + · simp only [h2, ↓reduceIte, getElem_cons_zero, add_zero, + Odd.add_one (Nat.not_even_iff_odd.mp h2)] + | k + 1 => + simp only [add_lt_add_iff_right] at hk h + simp only [getElem_cons_succ, h k hk] + ring_nf + have even_add_two (m : ℕ) : Even (2 + m) ↔ Even m := by + simp only [add_tsub_cancel_right, even_two, (Nat.even_sub (by omega : m ≤ 2 + m)).mp] + by_cases h_even : Even (n + k) + · rw [if_pos h_even] + rw [← even_add_two (n+k), ← Nat.add_assoc 2 n k] at h_even + rw [if_pos h_even] + · rw [if_neg h_even] + rw [← even_add_two (n+k), ← Nat.add_assoc 2 n k] at h_even + rw [if_neg h_even] + +lemma getElem_alternatingWord_swapIndices (i j : B) (p k : ℕ) (h : k + 1 < p) : + (alternatingWord i j p)[k+1]'(by simp; exact h) = + (alternatingWord j i p)[k]'(by simp [h]; omega) := by + rw [getElem_alternatingWord i j p (k+1) (by omega), getElem_alternatingWord j i p k (by omega)] + by_cases h_even : Even (p + k) + · rw [if_pos h_even, ← add_assoc] + simp only [ite_eq_right_iff, isEmpty_Prop, Nat.not_even_iff_odd, Even.add_one h_even, + IsEmpty.forall_iff] + · rw [if_neg h_even, ← add_assoc] + simp [Odd.add_one (Nat.not_even_iff_odd.mp h_even)] + +lemma listTake_alternatingWord (i j : B) (p k : ℕ) (h : k < 2 * p) : + List.take k (alternatingWord i j (2 * p)) = + if Even k then alternatingWord i j k else alternatingWord j i k := by + induction k with + | zero => + simp only [take_zero, even_zero, ↓reduceIte, alternatingWord] + | succ k h' => + have hk : k < 2 * p := by omega + apply h' at hk + by_cases h_even : Even k + · simp only [h_even, ↓reduceIte] at hk + simp only [Nat.not_even_iff_odd.mpr (Even.add_one h_even), ↓reduceIte] + rw [← List.take_concat_get _ _ (by simp[h]; omega), alternatingWord_succ, ← hk] + apply congr_arg + rw [getElem_alternatingWord i j (2*p) k (by omega)] + simp [(by apply Nat.even_add.mpr; simp[h_even]: Even (2 * p + k))] + · simp only [h_even, ↓reduceIte] at hk + simp only [(by simp at h_even; exact Odd.add_one h_even : Even (k + 1)), ↓reduceIte] + rw [← List.take_concat_get _ _ (by simp[h]; omega), alternatingWord_succ, hk] + apply congr_arg + rw [getElem_alternatingWord i j (2*p) k (by omega)] + simp [(by apply Nat.odd_add.mpr; simp[h_even]: Odd (2 * p + k))] + +lemma listTake_succ_alternatingWord (i j : B) (p : ℕ) (k : ℕ) (h : k + 1 < 2 * p) : + List.take (k + 1) (alternatingWord i j (2 * p)) = + i :: (List.take k (alternatingWord j i (2 * p))) := by + rw [listTake_alternatingWord j i p k (by omega), listTake_alternatingWord i j p (k+1) h] + + by_cases h_even : Even k + · simp [h_even, Nat.not_even_iff_odd.mpr (Even.add_one h_even), alternatingWord_succ', h_even] + · simp [h_even, (by simp at h_even; exact Odd.add_one h_even: Even (k + 1)), + alternatingWord_succ', h_even] + theorem prod_alternatingWord_eq_mul_pow (i i' : B) (m : ℕ) : π (alternatingWord i i' m) = (if Even m then 1 else s i') * (s i * s i') ^ (m / 2) := by induction' m with m ih diff --git a/Mathlib/GroupTheory/Coxeter/Inversion.lean b/Mathlib/GroupTheory/Coxeter/Inversion.lean index c5c613cf20c6a..b757715af2158 100644 --- a/Mathlib/GroupTheory/Coxeter/Inversion.lean +++ b/Mathlib/GroupTheory/Coxeter/Inversion.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2024 Mitchell Lee. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Mitchell Lee +Authors: Mitchell Lee, Óscar Álvarez -/ import Mathlib.GroupTheory.Coxeter.Length import Mathlib.Data.List.GetD @@ -255,6 +255,13 @@ theorem getD_rightInvSeq (ω : List B) (j : ℕ) : · simp only [getD_eq_getElem?_getD, get?_eq_getElem?] at ih simp [getD_cons_succ, ih j'] +lemma getElem_rightInvSeq (ω : List B) (j : ℕ) (h : j < ω.length) : + (ris ω)[j]'(by simp[h]) = + (π (ω.drop (j + 1)))⁻¹ + * (Option.map (cs.simple) (ω.get? j)).getD 1 + * π (ω.drop (j + 1)) := by + rw [← List.getD_eq_getElem (ris ω) 1, getD_rightInvSeq] + theorem getD_leftInvSeq (ω : List B) (j : ℕ) : (lis ω).getD j 1 = π (ω.take j) @@ -271,13 +278,19 @@ theorem getD_leftInvSeq (ω : List B) (j : ℕ) : rw [ih j'] simp [← mul_assoc, wordProd_cons] +lemma getElem_leftInvSeq (ω : List B) (j : ℕ) (h : j < ω.length) : + (lis ω)[j]'(by simp[h]) = + cs.wordProd (List.take j ω) * s ω[j] * (cs.wordProd (List.take j ω))⁻¹ := by + rw [← List.getD_eq_getElem (lis ω) 1, getD_leftInvSeq] + simp [h] + theorem getD_rightInvSeq_mul_self (ω : List B) (j : ℕ) : ((ris ω).getD j 1) * ((ris ω).getD j 1) = 1 := by simp_rw [getD_rightInvSeq, mul_assoc] rcases em (j < ω.length) with hj | nhj · rw [get?_eq_get hj] simp [← mul_assoc] - · rw [get?_eq_none.mpr (by omega)] + · rw [get?_eq_none_iff.mpr (by omega)] simp theorem getD_leftInvSeq_mul_self (ω : List B) (j : ℕ) : @@ -286,7 +299,7 @@ theorem getD_leftInvSeq_mul_self (ω : List B) (j : ℕ) : rcases em (j < ω.length) with hj | nhj · rw [get?_eq_get hj] simp [← mul_assoc] - · rw [get?_eq_none.mpr (by omega)] + · rw [get?_eq_none_iff.mpr (by omega)] simp theorem rightInvSeq_drop (ω : List B) (j : ℕ) : @@ -439,4 +452,38 @@ theorem IsReduced.nodup_leftInvSeq {ω : List B} (rω : cs.IsReduced ω) : List. apply nodup_rightInvSeq rwa [isReduced_reverse] +lemma getElem_succ_leftInvSeq_alternatingWord + (i j : B) (p k : ℕ) (h : k + 1 < 2 * p) : + (lis (alternatingWord i j (2 * p)))[k + 1]'(by simp; exact h) = + MulAut.conj (s i) ((lis (alternatingWord j i (2 * p)))[k]'(by simp; linarith)) := by + rw [cs.getElem_leftInvSeq (alternatingWord i j (2 * p)) (k + 1) (by simp[h]), + cs.getElem_leftInvSeq (alternatingWord j i (2 * p)) k (by simp[h]; omega)] + simp only [MulAut.conj, listTake_succ_alternatingWord i j p k h, cs.wordProd_cons, mul_assoc, + mul_inv_rev, inv_simple, MonoidHom.coe_mk, OneHom.coe_mk, MulEquiv.coe_mk, Equiv.coe_fn_mk, + mul_right_inj, mul_left_inj] + rw [getElem_alternatingWord_swapIndices i j (2 * p) k] + omega + +theorem getElem_leftInvSeq_alternatingWord + (i j : B) (p k : ℕ) (h : k < 2 * p) : + (lis (alternatingWord i j (2 * p)))[k]'(by simp; linarith) = + π alternatingWord j i (2 * k + 1) := by + revert i j + induction k with + | zero => + intro i j + simp only [CoxeterSystem.getElem_leftInvSeq cs (alternatingWord i j (2 * p)) 0 (by simp [h]), + take_zero, wordProd_nil, one_mul, inv_one, mul_one, alternatingWord, concat_eq_append, + nil_append, wordProd_singleton] + apply congr_arg + simp only [getElem_alternatingWord i j (2 * p) 0 (by simp [h]), add_zero, even_two, + Even.mul_right, ↓reduceIte] + | succ k hk => + intro i j + simp only [getElem_succ_leftInvSeq_alternatingWord cs i j p k h, hk (by omega), + MulAut.conj_apply, inv_simple, alternatingWord_succ' j i, even_two, Even.mul_right, + ↓reduceIte, wordProd_cons] + rw [(by ring: 2 * (k + 1) = 2 * k + 1 + 1), alternatingWord_succ j i, wordProd_concat] + simp [mul_assoc] + end CoxeterSystem diff --git a/Mathlib/GroupTheory/Exponent.lean b/Mathlib/GroupTheory/Exponent.lean index ea64a5ce67e5e..8adffc6d68bd0 100644 --- a/Mathlib/GroupTheory/Exponent.lean +++ b/Mathlib/GroupTheory/Exponent.lean @@ -439,7 +439,7 @@ theorem exists_orderOf_eq_exponent (hG : ExponentExists G) : ∃ g : G, orderOf nth_rw 1 [← pow_one p] have : 1 = (Nat.factorization (orderOf (t ^ p ^ k))) p + 1 := by rw [hpk', Nat.factorization_div hpk] - simp [hp] + simp [k, hp] rw [this] -- Porting note: convert made to_additive complain apply Nat.pow_succ_factorization_not_dvd (hG.orderOf_pos <| t ^ p ^ k).ne' hp diff --git a/Mathlib/GroupTheory/Goursat.lean b/Mathlib/GroupTheory/Goursat.lean index 90bc8ec652129..d24ea2e6457e4 100644 --- a/Mathlib/GroupTheory/Goursat.lean +++ b/Mathlib/GroupTheory/Goursat.lean @@ -76,11 +76,13 @@ lemma mk_goursatFst_eq_iff_mk_goursatSnd_eq {x y : G × H} (hx : x ∈ I) (hy : · simpa [Prod.mul_def, Prod.div_def] using div_mem (mul_mem h hx) hy · simpa [Prod.mul_def, Prod.div_def] using div_mem (mul_mem h hy) hx +variable (I) in +@[to_additive AddSubgroup.goursatFst_prod_goursatSnd_le] lemma goursatFst_prod_goursatSnd_le : I.goursatFst.prod I.goursatSnd ≤ I := by rintro ⟨g, h⟩ ⟨hg, hh⟩ simpa using mul_mem (mem_goursatFst.1 hg) (mem_goursatSnd.1 hh) -/-- **Goursat's lemma** for a subgroup of with surjective projections. +/-- **Goursat's lemma** for a subgroup of a product with surjective projections. If `I` is a subgroup of `G × H` which projects fully on both factors, then there exist normal subgroups `M ≤ G` and `N ≤ H` such that `G' × H' ≤ I` and the image of `I` in `G ⧸ M × H ⧸ N` is the @@ -88,7 +90,7 @@ graph of an isomorphism `G ⧸ M ≃ H ⧸ N'`. `G'` and `H'` can be explicitly constructed as `I.goursatFst` and `I.goursatSnd` respectively. -/ @[to_additive -"**Goursat's lemma** for a subgroup of with surjective projections. +"**Goursat's lemma** for a subgroup of a product with surjective projections. If `I` is a subgroup of `G × H` which projects fully on both factors, then there exist normal subgroups `M ≤ G` and `N ≤ H` such that `G' × H' ≤ I` and the image of `I` in `G ⧸ M × H ⧸ N` is the @@ -111,8 +113,8 @@ lemma goursat_surjective : /-- **Goursat's lemma** for an arbitrary subgroup. If `I` is a subgroup of `G × H`, then there exist subgroups `G' ≤ G`, `H' ≤ H` and normal subgroups -`M ≤ G'` and `N ≤ H'` such that `M × N ≤ I` and the image of `I` in `G' ⧸ M × H' ⧸ N` is the graph -of an isomorphism `G ⧸ G' ≃ H ⧸ H'`. -/ +`M ⊴ G'` and `N ⊴ H'` such that `M × N ≤ I` and the image of `I` in `G' ⧸ M × H' ⧸ N` is the graph +of an isomorphism `G' ⧸ M ≃ H' ⧸ N`. -/ @[to_additive "**Goursat's lemma** for an arbitrary subgroup. @@ -150,29 +152,21 @@ lemma goursat : · ext ⟨g, h⟩ constructor · intro hgh - simpa only [mem_map, MonoidHom.mem_range, MonoidHom.prod_apply, Subtype.exists, Prod.exists, - MonoidHom.coe_prodMap, coeSubtype, Prod.mk.injEq, Prod.map_apply, MonoidHom.coe_snd, - exists_eq_right, exists_and_right, exists_eq_right_right, MonoidHom.coe_fst] + simpa only [G', H', mem_map, MonoidHom.mem_range, MonoidHom.prod_apply, Subtype.exists, + Prod.exists, MonoidHom.coe_prodMap, coeSubtype, Prod.mk.injEq, Prod.map_apply, + MonoidHom.coe_snd, exists_eq_right, exists_and_right, exists_eq_right_right, + MonoidHom.coe_fst] using ⟨⟨h, hgh⟩, ⟨g, hgh⟩, g, h, hgh, ⟨rfl, rfl⟩⟩ - · simp only [mem_map, MonoidHom.mem_range, MonoidHom.prod_apply, Subtype.exists, Prod.exists, - MonoidHom.coe_prodMap, coeSubtype, Prod.mk.injEq, Prod.map_apply, MonoidHom.coe_snd, - exists_eq_right, exists_and_right, exists_eq_right_right, MonoidHom.coe_fst, - forall_exists_index, and_imp] + · simp only [G', H', mem_map, MonoidHom.mem_range, MonoidHom.prod_apply, Subtype.exists, + Prod.exists, MonoidHom.coe_prodMap, coeSubtype, Prod.mk.injEq, Prod.map_apply, + MonoidHom.coe_snd, exists_eq_right, exists_and_right, exists_eq_right_right, + MonoidHom.coe_fst, forall_exists_index, and_imp] rintro h₁ hgh₁ g₁ hg₁h g₂ h₂ hg₂h₂ hP hQ simp only [Subtype.ext_iff] at hP hQ rwa [← hP, ← hQ] - · rintro ⟨⟨g, _⟩, ⟨h, _⟩⟩ hgh - simp only [MonoidHom.prodMap, MonoidHom.mem_ker, MonoidHom.prod_apply, MonoidHom.coe_comp, - QuotientGroup.coe_mk', MonoidHom.coe_fst, comp_apply, MonoidHom.coe_snd, Prod.mk_eq_one, - QuotientGroup.eq_one_iff, mem_goursatFst, MonoidHom.mem_range, Prod.mk.injEq, Subtype.exists, - Prod.exists, mem_goursatSnd] at hgh - rcases hgh with ⟨⟨g₁, h₁, hg₁h₁, hPQ₁⟩, ⟨g₂, h₂, hg₂h₂, hPQ₂⟩⟩ - simp only [Subtype.ext_iff] at hPQ₁ hPQ₂ - rcases hPQ₁ with ⟨rfl, rfl⟩ - rcases hPQ₂ with ⟨rfl, rfl⟩ - simp only [MonoidHom.mem_range, MonoidHom.prod_apply, Prod.mk.injEq, Subtype.exists, - Prod.exists] - refine ⟨g₁, h₂, ?_, rfl, rfl⟩ - simpa only [OneMemClass.coe_one, Prod.mk_mul_mk, mul_one, one_mul] using mul_mem hg₁h₁ hg₂h₂ + · convert goursatFst_prod_goursatSnd_le (P.prod Q).range + ext ⟨g, h⟩ + simp_rw [G', H', MonoidHom.mem_ker, MonoidHom.coe_prodMap, Prod.map_apply, Subgroup.mem_prod, + Prod.one_eq_mk, Prod.ext_iff, ← MonoidHom.mem_ker, QuotientGroup.ker_mk'] end Subgroup diff --git a/Mathlib/GroupTheory/GroupAction/Basic.lean b/Mathlib/GroupTheory/GroupAction/Basic.lean index ae7eaef28b78d..7ea1e10af8050 100644 --- a/Mathlib/GroupTheory/GroupAction/Basic.lean +++ b/Mathlib/GroupTheory/GroupAction/Basic.lean @@ -5,7 +5,6 @@ Authors: Chris Hughes -/ import Mathlib.Algebra.Group.Subgroup.Map import Mathlib.Data.Finite.Sigma -import Mathlib.Data.Set.Finite.Basic import Mathlib.Data.Set.Finite.Range import Mathlib.Data.Set.Pointwise.SMul import Mathlib.Data.Setoid.Basic @@ -291,29 +290,4 @@ theorem le_stabilizer_iff_smul_le (s : Set α) (H : Subgroup G) : simp only [Set.smul_mem_smul_set_iff, hx] · simp only [smul_inv_smul] -/-- To prove membership to stabilizer of a *finite set*, it is enough to prove one inclusion. -/ -theorem mem_stabilizer_of_finite_iff_smul_le (s : Set α) (hs : s.Finite) (g : G) : - g ∈ stabilizer G s ↔ g • s ⊆ s := by - haveI : Fintype s := Set.Finite.fintype hs - haveI : Finite (g • s : Set α) := Finite.Set.finite_image .. - haveI : Fintype (g • s : Set α) := Fintype.ofFinite _ - rw [mem_stabilizer_iff] - constructor - · exact Eq.subset - · rw [← Set.toFinset_inj, ← Set.toFinset_subset_toFinset] - intro h - apply Finset.eq_of_subset_of_card_le h - apply le_of_eq - suffices (g • s).toFinset = Finset.map ⟨_, MulAction.injective g⟩ hs.toFinset by - rw [this, Finset.card_map, Set.toFinite_toFinset] - rw [← Finset.coe_inj] - simp only [Set.coe_toFinset, Set.toFinite_toFinset, Finset.coe_map, - Function.Embedding.coeFn_mk, Set.image_smul] - -/-- To prove membership to stabilizer of a *finite set*, it is enough to prove one inclusion. -/ -theorem mem_stabilizer_of_finite_iff_le_smul (s : Set α) (hs : s.Finite) (g : G) : - g ∈ stabilizer G s ↔ s ⊆ g • s := by - rw [← @inv_mem_iff, mem_stabilizer_of_finite_iff_smul_le s hs] - exact Set.subset_set_smul_iff.symm - end MulAction diff --git a/Mathlib/GroupTheory/GroupAction/Blocks.lean b/Mathlib/GroupTheory/GroupAction/Blocks.lean index e3372fa4417f0..99a9a8640fb29 100644 --- a/Mathlib/GroupTheory/GroupAction/Blocks.lean +++ b/Mathlib/GroupTheory/GroupAction/Blocks.lean @@ -3,6 +3,7 @@ Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Antoine Chambert-Loir -/ +import Mathlib.Algebra.Pointwise.Stabilizer import Mathlib.Data.Setoid.Partition import Mathlib.GroupTheory.GroupAction.Pointwise import Mathlib.GroupTheory.GroupAction.SubMulAction @@ -105,7 +106,7 @@ def IsTrivialBlock (B : Set X) := B.Subsingleton ∨ B = univ "A set `B` is a `G`-block iff the sets of the form `g +ᵥ B` are pairwise equal or disjoint. "] def IsBlock (B : Set X) := ∀ ⦃g₁ g₂ : G⦄, g₁ • B ≠ g₂ • B → Disjoint (g₁ • B) (g₂ • B) -variable {G} +variable {G} {s : Set G} {g g₁ g₂ : G} @[to_additive] lemma isBlock_iff_smul_eq_smul_of_nonempty : @@ -121,6 +122,27 @@ lemma isBlock_iff_smul_eq_smul_or_disjoint : IsBlock G B ↔ ∀ g₁ g₂ : G, g₁ • B = g₂ • B ∨ Disjoint (g₁ • B) (g₂ • B) := forall₂_congr fun _ _ ↦ or_iff_not_imp_left.symm +@[to_additive] +lemma IsBlock.smul_eq_smul_of_subset (hB : IsBlock G B) (hg : g₁ • B ⊆ g₂ • B) : + g₁ • B = g₂ • B := by + by_contra! hg' + obtain rfl : B = ∅ := by simpa using (hB hg').eq_bot_of_le hg + simp at hg' + +@[to_additive] +lemma IsBlock.not_smul_set_ssubset_smul_set (hB : IsBlock G B) : ¬ g₁ • B ⊂ g₂ • B := + fun hab ↦ hab.ne <| hB.smul_eq_smul_of_subset hab.subset + +@[to_additive] +lemma IsBlock.disjoint_smul_set_smul (hB : IsBlock G B) (hgs : ¬ g • B ⊆ s • B) : + Disjoint (g • B) (s • B) := by + rw [← iUnion_smul_set, disjoint_iUnion₂_right] + exact fun b hb ↦ hB fun h ↦ hgs <| h.trans_subset <| smul_set_subset_smul hb + +@[to_additive] +lemma IsBlock.disjoint_smul_smul_set (hB : IsBlock G B) (hgs : ¬ g • B ⊆ s • B) : + Disjoint (s • B) (g • B) := (hB.disjoint_smul_set_smul hgs).symm + alias ⟨IsBlock.smul_eq_smul_of_nonempty, _⟩ := isBlock_iff_smul_eq_smul_of_nonempty alias ⟨IsBlock.pairwiseDisjoint_range_smul, _⟩ := isBlock_iff_pairwiseDisjoint_range_smul alias ⟨IsBlock.smul_eq_smul_or_disjoint, _⟩ := isBlock_iff_smul_eq_smul_or_disjoint @@ -149,6 +171,19 @@ lemma IsFixedBlock.isInvariantBlock (hB : IsFixedBlock G B) : IsInvariantBlock G end SMul +section Monoid +variable {M X : Type*} [Monoid M] [MulAction M X] {B : Set X} {s : Set M} + +@[to_additive] +lemma IsBlock.disjoint_smul_right (hB : IsBlock M B) (hs : ¬ B ⊆ s • B) : Disjoint B (s • B) := by + simpa using hB.disjoint_smul_set_smul (g := 1) (by simpa using hs) + +@[to_additive] +lemma IsBlock.disjoint_smul_left (hB : IsBlock M B) (hs : ¬ B ⊆ s • B) : Disjoint (s • B) B := + (hB.disjoint_smul_right hs).symm + +end Monoid + section Group variable {G : Type*} [Group G] {X : Type*} [MulAction G X] {B : Set X} @@ -553,7 +588,7 @@ theorem of_subset (a : X) (hfB : B.Finite) : smul_smul, ← mul_inv_rev] at hg hx ⊢ exact fun _ ↦ hx _ ∘ hg _ have hag' (g : G) (hg : a ∈ g • B') : B' = g • B' := by - rw [eq_comm, ← mem_stabilizer_iff, mem_stabilizer_of_finite_iff_le_smul _ hfB'] + rw [eq_comm, ← mem_stabilizer_iff, mem_stabilizer_set_iff_subset_smul_set hfB'] exact hag g hg rw [isBlock_iff_smul_eq_of_nonempty] rintro g ⟨b : X, hb' : b ∈ g • B', hb : b ∈ B'⟩ diff --git a/Mathlib/GroupTheory/GroupAction/Hom.lean b/Mathlib/GroupTheory/GroupAction/Hom.lean index 2ce20e3e8812b..f10d91924ee1c 100644 --- a/Mathlib/GroupTheory/GroupAction/Hom.lean +++ b/Mathlib/GroupTheory/GroupAction/Hom.lean @@ -150,10 +150,6 @@ theorem map_smul {F M X Y : Type*} [SMul M X] [SMul M Y] (f : F) (c : M) (x : X) : f (c • x) = c • f x := map_smulₛₗ f c x --- attribute [simp] map_smulₛₗ - --- Porting note: removed has_coe_to_fun instance, coercions handled differently now - @[to_additive] instance : MulActionSemiHomClass (X →ₑ[φ] Y) φ X Y where map_smulₛₗ := MulActionHom.map_smul' @@ -166,8 +162,6 @@ namespace MulActionHom variable {φ X Y} variable {F : Type*} [FunLike F X Y] -/- porting note: inserted following def & instance for consistent coercion behaviour, -see also Algebra.Hom.Group -/ /-- Turn an element of a type `F` satisfying `MulActionSemiHomClass F φ X Y` into an actual `MulActionHom`. This is declared as the default coercion from `F` to `MulActionSemiHom φ X Y`. -/ @@ -417,14 +411,6 @@ abbrev DistribMulActionHomClass (F : Type*) (M : outParam Type*) namespace DistribMulActionHom -/- Porting note (https://github.com/leanprover-community/mathlib4/issues/11215): TODO decide whether the next two instances should be removed -Coercion is already handled by all the HomClass constructions I believe -/ --- instance coe : Coe (A →+[M] B) (A →+ B) := --- ⟨toAddMonoidHom⟩ - --- instance coe' : Coe (A →+[M] B) (A →[M] B) := --- ⟨toMulActionHom⟩ - instance : FunLike (A →ₑ+[φ] B) A B where coe m := m.toFun coe_injective' f g h := by @@ -439,8 +425,6 @@ instance : DistribMulActionSemiHomClass (A →ₑ+[φ] B) φ A B where variable {φ φ' A B B₁} variable {F : Type*} [FunLike F A B] -/- porting note: inserted following def & instance for consistent coercion behaviour, -see also Algebra.Hom.Group -/ /-- Turn an element of a type `F` satisfying `MulActionHomClass F M X Y` into an actual `MulActionHom`. This is declared as the default coercion from `F` to `MulActionHom M X Y`. -/ @[coe] @@ -518,9 +502,8 @@ theorem id_apply (x : A) : DistribMulActionHom.id M x = x := by variable {M C ψ χ} --- porting note: `simp` used to prove this, but now `change` is needed to push past the coercions instance : Zero (A →ₑ+[φ] B) := - ⟨{ (0 : A →+ B) with map_smul' := fun m _ => by change (0 : B) = (φ m) • (0 : B); rw [smul_zero]}⟩ + ⟨{ (0 : A →+ B) with map_smul' := fun m _ => by simp }⟩ instance : One (A →+[M] A) := ⟨DistribMulActionHom.id M⟩ @@ -659,18 +642,6 @@ abbrev MulSemiringActionHomClass namespace MulSemiringActionHom -/- Porting note (https://github.com/leanprover-community/mathlib4/issues/11215): TODO decide whether the next two instances should be removed -Coercion is already handled by all the HomClass constructions I believe -/ --- @[coe] --- instance coe : Coe (R →+*[M] S) (R →+* S) := --- ⟨toRingHom⟩ - --- @[coe] --- instance coe' : Coe (R →+*[M] S) (R →+[M] S) := --- ⟨toDistribMulActionHom⟩ - --- Porting note: removed has_coe_to_fun instance, coercions handled differently now - instance : FunLike (R →ₑ+*[φ] S) R S where coe m := m.toFun coe_injective' f g h := by @@ -687,8 +658,6 @@ instance : MulSemiringActionSemiHomClass (R →ₑ+*[φ] S) φ R S where variable {φ R S} variable {F : Type*} [FunLike F R S] -/- porting note: inserted following def & instance for consistent coercion behaviour, -see also Algebra.Hom.Group -/ /-- Turn an element of a type `F` satisfying `MulSemiringActionHomClass F M R S` into an actual `MulSemiringActionHom`. This is declared as the default coercion from `F` to `MulSemiringActionHom M X Y`. -/ diff --git a/Mathlib/GroupTheory/HNNExtension.lean b/Mathlib/GroupTheory/HNNExtension.lean index 2c932f875279a..79dab5bd2e7c8 100644 --- a/Mathlib/GroupTheory/HNNExtension.lean +++ b/Mathlib/GroupTheory/HNNExtension.lean @@ -679,8 +679,8 @@ theorem toList_eq_nil_of_mem_of_range (w : ReducedWord G A B) w.toList = [] := by rcases hw with ⟨g, hg⟩ let w' : ReducedWord G A B := { ReducedWord.empty G A B with head := g } - have : w.prod φ = w'.prod φ := by simp [ReducedWord.prod, hg] - simpa using (map_fst_eq_and_of_prod_eq φ this).1 + have : w.prod φ = w'.prod φ := by simp [w', ReducedWord.prod, hg] + simpa [w'] using (map_fst_eq_and_of_prod_eq φ this).1 end ReducedWord diff --git a/Mathlib/GroupTheory/Order/Min.lean b/Mathlib/GroupTheory/Order/Min.lean index 3d1047b06f179..3b1ced396e120 100644 --- a/Mathlib/GroupTheory/Order/Min.lean +++ b/Mathlib/GroupTheory/Order/Min.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies -/ import Mathlib.GroupTheory.Torsion +import Mathlib.Data.ENat.Lattice /-! # Minimum order of an element diff --git a/Mathlib/GroupTheory/OrderOfElement.lean b/Mathlib/GroupTheory/OrderOfElement.lean index 564cc2da28dcb..492cc93e69891 100644 --- a/Mathlib/GroupTheory/OrderOfElement.lean +++ b/Mathlib/GroupTheory/OrderOfElement.lean @@ -10,6 +10,7 @@ import Mathlib.Algebra.Order.Group.Action import Mathlib.Algebra.Order.Ring.Abs import Mathlib.GroupTheory.Index import Mathlib.Order.Interval.Set.Infinite +import Mathlib.Tactic.Positivity /-! # Order of an element diff --git a/Mathlib/GroupTheory/Perm/Cycle/Type.lean b/Mathlib/GroupTheory/Perm/Cycle/Type.lean index 7b8e2f1c0b26d..b47673b955137 100644 --- a/Mathlib/GroupTheory/Perm/Cycle/Type.lean +++ b/Mathlib/GroupTheory/Perm/Cycle/Type.lean @@ -394,12 +394,12 @@ section Cauchy variable (G : Type*) [Group G] (n : ℕ) /-- The type of vectors with terms from `G`, length `n`, and product equal to `1:G`. -/ -def vectorsProdEqOne : Set (Vector G n) := +def vectorsProdEqOne : Set (Mathlib.Vector G n) := { v | v.toList.prod = 1 } namespace VectorsProdEqOne -theorem mem_iff {n : ℕ} (v : Vector G n) : v ∈ vectorsProdEqOne G n ↔ v.toList.prod = 1 := +theorem mem_iff {n : ℕ} (v : Mathlib.Vector G n) : v ∈ vectorsProdEqOne G n ↔ v.toList.prod = 1 := Iff.rfl theorem zero_eq : vectorsProdEqOne G 0 = {Vector.nil} := @@ -421,7 +421,7 @@ instance oneUnique : Unique (vectorsProdEqOne G 1) := by /-- Given a vector `v` of length `n`, make a vector of length `n + 1` whose product is `1`, by appending the inverse of the product of `v`. -/ @[simps] -def vectorEquiv : Vector G n ≃ vectorsProdEqOne G (n + 1) where +def vectorEquiv : Mathlib.Vector G n ≃ vectorsProdEqOne G (n + 1) where toFun v := ⟨v.toList.prod⁻¹ ::ᵥ v, by rw [mem_iff, Vector.toList_cons, List.prod_cons, inv_mul_cancel]⟩ invFun v := v.1.tail @@ -436,12 +436,12 @@ def vectorEquiv : Vector G n ≃ vectorsProdEqOne G (n + 1) where /-- Given a vector `v` of length `n` whose product is 1, make a vector of length `n - 1`, by deleting the last entry of `v`. -/ -def equivVector : ∀ n, vectorsProdEqOne G n ≃ Vector G (n - 1) +def equivVector : ∀ n, vectorsProdEqOne G n ≃ Mathlib.Vector G (n - 1) | 0 => (equivOfUnique (vectorsProdEqOne G 0) (vectorsProdEqOne G 1)).trans (vectorEquiv G 0).symm | (n + 1) => (vectorEquiv G n).symm instance [Fintype G] : Fintype (vectorsProdEqOne G n) := - Fintype.ofEquiv (Vector G (n - 1)) (equivVector G n).symm + Fintype.ofEquiv (Mathlib.Vector G (n - 1)) (equivVector G n).symm theorem card [Fintype G] : Fintype.card (vectorsProdEqOne G n) = Fintype.card G ^ (n - 1) := (Fintype.card_congr (equivVector G n)).trans (card_vector (n - 1)) diff --git a/Mathlib/GroupTheory/Perm/Sign.lean b/Mathlib/GroupTheory/Perm/Sign.lean index bfb55453b7c78..9ef9e1f4486bd 100644 --- a/Mathlib/GroupTheory/Perm/Sign.lean +++ b/Mathlib/GroupTheory/Perm/Sign.lean @@ -5,10 +5,11 @@ Authors: Chris Hughes -/ import Mathlib.Algebra.Group.Conj import Mathlib.Algebra.Group.Subgroup.Lattice -import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Algebra.Ring.Int.Units import Mathlib.Data.Finset.Fin import Mathlib.Data.Finset.Sort +import Mathlib.Data.Fintype.Perm import Mathlib.Data.Fintype.Prod import Mathlib.Data.Fintype.Sum import Mathlib.Data.Int.Order.Units @@ -597,4 +598,29 @@ end congr end SignType.sign +section Finset + +variable [Fintype α] + +/-- Permutations of a given sign. -/ +def ofSign (s : ℤˣ) : Finset (Perm α) := univ.filter (sign · = s) + +@[simp] +lemma mem_ofSign {s : ℤˣ} {σ : Perm α} : σ ∈ ofSign s ↔ σ.sign = s := by + rw [ofSign, mem_filter, and_iff_right (mem_univ σ)] + +lemma ofSign_disjoint : _root_.Disjoint (ofSign 1 : Finset (Perm α)) (ofSign (-1)) := by + rw [Finset.disjoint_iff_ne] + rintro σ hσ τ hτ rfl + rw [mem_ofSign] at hσ hτ + have := hσ.symm.trans hτ + contradiction + +lemma ofSign_disjUnion : + (ofSign 1).disjUnion (ofSign (-1)) ofSign_disjoint = (univ : Finset (Perm α)) := by + ext σ + simp_rw [mem_disjUnion, mem_ofSign, Int.units_eq_one_or, mem_univ] + +end Finset + end Equiv.Perm diff --git a/Mathlib/GroupTheory/PushoutI.lean b/Mathlib/GroupTheory/PushoutI.lean index 0f672f3da1e25..c275a0b83ee72 100644 --- a/Mathlib/GroupTheory/PushoutI.lean +++ b/Mathlib/GroupTheory/PushoutI.lean @@ -425,7 +425,7 @@ noncomputable def equivPair (i) : NormalWord d ≃ Pair d i := exact w.normalized _ _ (Word.mem_of_mem_equivPair_tail _ hg) } haveI leftInv : Function.LeftInverse (rcons i) toFun := fun w => ext_smul i <| by - simp only [rcons, Word.equivPair_symm, + simp only [toFun, rcons, Word.equivPair_symm, Word.equivPair_smul_same, Word.equivPair_tail_eq_inv_smul, Word.rcons_eq_smul, MonoidHom.apply_ofInjective_symm, equiv_fst_eq_mul_inv, mul_assoc, map_mul, map_inv, mul_smul, inv_smul_smul, smul_inv_smul] @@ -679,11 +679,12 @@ theorem inf_of_range_eq_base_range exact hx (of_apply_eq_base φ j y ▸ MonoidHom.mem_range.2 ⟨y, rfl⟩) let w : Word G := ⟨[⟨_, g₁⟩, ⟨_, g₂⁻¹⟩], by simp_all, by simp_all⟩ have hw : Reduced φ w := by - simp only [not_exists, ne_eq, Reduced, List.find?, List.mem_cons, List.mem_singleton, - forall_eq_or_imp, not_false_eq_true, forall_const, forall_eq, true_and, hg₁r, hg₂r, - List.mem_nil_iff, false_imp_iff, imp_true_iff, and_true, inv_mem_iff] + simp only [w, not_exists, ne_eq, Reduced, List.find?, List.mem_cons, + List.mem_singleton, forall_eq_or_imp, not_false_eq_true, forall_const, forall_eq, + true_and, hg₁r, hg₂r, List.mem_nil_iff, false_imp_iff, imp_true_iff, and_true, + inv_mem_iff] have := hw.eq_empty_of_mem_range hφ (by - simp only [Word.prod, List.map_cons, List.prod_cons, List.prod_nil, + simp only [w, Word.prod, List.map_cons, List.prod_cons, List.prod_nil, List.map_nil, map_mul, ofCoprodI_of, hg₁, hg₂, map_inv, map_one, mul_one, mul_inv_cancel, one_mem]) simp [w, Word.empty] at this) diff --git a/Mathlib/GroupTheory/QuotientGroup/Basic.lean b/Mathlib/GroupTheory/QuotientGroup/Basic.lean index 3c1822db6828d..58622e2d53e83 100644 --- a/Mathlib/GroupTheory/QuotientGroup/Basic.lean +++ b/Mathlib/GroupTheory/QuotientGroup/Basic.lean @@ -10,6 +10,7 @@ import Mathlib.Data.Int.Cast.Lemmas import Mathlib.GroupTheory.Congruence.Hom import Mathlib.GroupTheory.Coset.Basic import Mathlib.GroupTheory.QuotientGroup.Defs +import Mathlib.Algebra.BigOperators.Group.Finset /-! # Quotients of groups by normal subgroups diff --git a/Mathlib/GroupTheory/SpecificGroups/ZGroup.lean b/Mathlib/GroupTheory/SpecificGroups/ZGroup.lean index 6cb4009aa11c0..f2d850b5a8d40 100644 --- a/Mathlib/GroupTheory/SpecificGroups/ZGroup.lean +++ b/Mathlib/GroupTheory/SpecificGroups/ZGroup.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Thomas Browning -/ import Mathlib.Algebra.Squarefree.Basic -import Mathlib.GroupTheory.Sylow +import Mathlib.GroupTheory.Nilpotent /-! # Z-Groups @@ -30,6 +30,9 @@ variable {G G' f} namespace IsZGroup +instance [IsZGroup G] {p : ℕ} [Fact p.Prime] (P : Sylow p G) : IsCyclic P := + isZGroup p Fact.out P + theorem of_squarefree (hG : Squarefree (Nat.card G)) : IsZGroup G := by have : Finite G := Nat.finite_of_card_ne_zero hG.ne_zero refine ⟨fun p hp P ↦ ?_⟩ @@ -59,4 +62,24 @@ theorem of_surjective [Finite G] [hG : IsZGroup G] (hf : Function.Surjective f) instance [Finite G] [IsZGroup G] (H : Subgroup G) [H.Normal] : IsZGroup (G ⧸ H) := of_surjective (QuotientGroup.mk'_surjective H) +theorem exponent_eq_card [Finite G] [IsZGroup G] : Monoid.exponent G = Nat.card G := by + refine dvd_antisymm Group.exponent_dvd_nat_card ?_ + rw [← Nat.factorization_prime_le_iff_dvd Nat.card_pos.ne' Monoid.exponent_ne_zero_of_finite] + intro p hp + have := Fact.mk hp + let P : Sylow p G := default + rw [← hp.pow_dvd_iff_le_factorization Monoid.exponent_ne_zero_of_finite, + ← P.card_eq_multiplicity, ← (isZGroup p hp P).exponent_eq_card] + exact Monoid.exponent_dvd_of_monoidHom P.1.subtype P.1.subtype_injective + +instance [Finite G] [IsZGroup G] [hG : Group.IsNilpotent G] : IsCyclic G := by + have (p : { x // x ∈ (Nat.card G).primeFactors }) : Fact p.1.Prime := + ⟨Nat.prime_of_mem_primeFactors p.2⟩ + let h (p : { x // x ∈ (Nat.card G).primeFactors }) (P : Sylow p G) : CommGroup P := + IsCyclic.commGroup + obtain ⟨ϕ⟩ := ((isNilpotent_of_finite_tfae (G := G)).out 0 4).mp hG + let _ : CommGroup G := + ⟨fun g h ↦ by rw [← ϕ.symm.injective.eq_iff, map_mul, mul_comm, ← map_mul]⟩ + exact IsCyclic.of_exponent_eq_card exponent_eq_card + end IsZGroup diff --git a/Mathlib/Lean/Meta/DiscrTree.lean b/Mathlib/Lean/Meta/DiscrTree.lean index 4698847cefc5a..586b3f28ad8c3 100644 --- a/Mathlib/Lean/Meta/DiscrTree.lean +++ b/Mathlib/Lean/Meta/DiscrTree.lean @@ -24,21 +24,21 @@ so that we return lemmas matching larger subexpressions first, and amongst those we return more specific lemmas first. -/ partial def getSubexpressionMatches {α : Type} - (d : DiscrTree α) (e : Expr) (config : WhnfCoreConfig) : MetaM (Array α) := do + (d : DiscrTree α) (e : Expr) : MetaM (Array α) := do match e with | .bvar _ => return #[] | .forallE _ _ _ _ => forallTelescope e (fun args body => do args.foldlM (fun acc arg => do - pure <| acc ++ (← d.getSubexpressionMatches (← inferType arg) config)) - (← d.getSubexpressionMatches body config).reverse) + pure <| acc ++ (← d.getSubexpressionMatches (← inferType arg))) + (← d.getSubexpressionMatches body).reverse) | .lam _ _ _ _ | .letE _ _ _ _ _ => lambdaLetTelescope e (fun args body => do args.foldlM (fun acc arg => do - pure <| acc ++ (← d.getSubexpressionMatches (← inferType arg) config)) - (← d.getSubexpressionMatches body config).reverse) + pure <| acc ++ (← d.getSubexpressionMatches (← inferType arg))) + (← d.getSubexpressionMatches body).reverse) | _ => e.foldlM (fun a f => do - pure <| a ++ (← d.getSubexpressionMatches f config)) (← d.getMatch e config).reverse + pure <| a ++ (← d.getSubexpressionMatches f)) (← d.getMatch e).reverse /-- Check if a `keys : Array DiscTree.Key` is "specific", diff --git a/Mathlib/Lean/Meta/KAbstractPositions.lean b/Mathlib/Lean/Meta/KAbstractPositions.lean index 60d3ded29a824..ffb5899f96568 100644 --- a/Mathlib/Lean/Meta/KAbstractPositions.lean +++ b/Mathlib/Lean/Meta/KAbstractPositions.lean @@ -71,7 +71,7 @@ def viewKAbstractSubExpr (e : Expr) (pos : SubExpr.Pos) : MetaM (Option (Expr × if subExpr.hasLooseBVars then return none let positions ← kabstractPositions subExpr e - let some n := positions.getIdx? pos | unreachable! + let some n := positions.indexOf? pos | unreachable! return some (subExpr, if positions.size == 1 then none else some (n + 1)) /-- Determine whether the result of abstracting `subExpr` from `e` at position `pos` results diff --git a/Mathlib/Lean/Meta/Simp.lean b/Mathlib/Lean/Meta/Simp.lean index 5f38f103a0dcc..289c25c8f0e60 100644 --- a/Mathlib/Lean/Meta/Simp.lean +++ b/Mathlib/Lean/Meta/Simp.lean @@ -72,10 +72,10 @@ def simpTheoremsOfNames (lemmas : List Name := []) (simpOnly : Bool := false) : /-- Construct a `Simp.Context` from a list of names. -/ def Simp.Context.ofNames (lemmas : List Name := []) (simpOnly : Bool := false) - (config : Simp.Config := {}) : MetaM Simp.Context := do pure <| - { simpTheorems := #[← simpTheoremsOfNames lemmas simpOnly], - congrTheorems := ← Lean.Meta.getSimpCongrTheorems, - config := config } + (config : Simp.Config := {}) : MetaM Simp.Context := do + Simp.mkContext config + (simpTheorems := #[← simpTheoremsOfNames lemmas simpOnly]) + (congrTheorems := ← Lean.Meta.getSimpCongrTheorems) /-- Simplify an expression using only a list of lemmas specified by name. -/ def simpOnlyNames (lemmas : List Name) (e : Expr) (config : Simp.Config := {}) : diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean index 75e11673b7d74..1ac5e28cebf7a 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineEquiv.lean @@ -467,7 +467,7 @@ open Function def pointReflection (x : P₁) : P₁ ≃ᵃ[k] P₁ := (constVSub k x).trans (vaddConst k x) -theorem pointReflection_apply (x y : P₁) : pointReflection k x y = x -ᵥ y +ᵥ x := +theorem pointReflection_apply (x y : P₁) : pointReflection k x y = (x -ᵥ y) +ᵥ x := rfl @[simp] diff --git a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean index 4ad30ae06cd1d..b62ed22785418 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/AffineSubspace.lean @@ -258,7 +258,8 @@ theorem coe_direction_eq_vsub_set_right {s : AffineSubspace k P} {p : P} (hp : p rw [coe_direction_eq_vsub_set ⟨p, hp⟩] refine le_antisymm ?_ ?_ · rintro v ⟨p1, hp1, p2, hp2, rfl⟩ - exact ⟨p1 -ᵥ p2 +ᵥ p, vadd_mem_of_mem_direction (vsub_mem_direction hp1 hp2) hp, vadd_vsub _ _⟩ + exact ⟨(p1 -ᵥ p2) +ᵥ p, + vadd_mem_of_mem_direction (vsub_mem_direction hp1 hp2) hp, vadd_vsub _ _⟩ · rintro v ⟨p2, hp2, rfl⟩ exact ⟨p2, hp2, p, hp, rfl⟩ @@ -686,7 +687,7 @@ theorem direction_top : (⊤ : AffineSubspace k P).direction = ⊤ := by cases' S.nonempty with p ext v refine ⟨imp_intro Submodule.mem_top, fun _hv => ?_⟩ - have hpv : (v +ᵥ p -ᵥ p : V) ∈ (⊤ : AffineSubspace k P).direction := + have hpv : ((v +ᵥ p) -ᵥ p : V) ∈ (⊤ : AffineSubspace k P).direction := vsub_mem_direction (mem_top k V _) (mem_top k V _) rwa [vadd_vsub] at hpv @@ -1249,7 +1250,7 @@ theorem affineSpan_pair_le_of_right_mem {p₁ p₂ p₃ : P} (h : p₁ ∈ line[ variable (k) /-- `affineSpan` is monotone. -/ -@[mono] +@[gcongr, mono] theorem affineSpan_mono {s₁ s₂ : Set P} (h : s₁ ⊆ s₂) : affineSpan k s₁ ≤ affineSpan k s₂ := spanPoints_subset_coe_of_subset_coe (Set.Subset.trans h (subset_affineSpan k _)) diff --git a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean index 7170f542e27e4..25dfb8d294ad8 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Combination.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Combination.lean @@ -412,9 +412,9 @@ theorem attach_affineCombination_of_injective [DecidableEq P] (s : Finset P) (w change univ.sum g₁ = (image f univ).sum g₂ have hgf : g₁ = g₂ ∘ f := by ext - simp + simp [g₁, g₂] rw [hgf, sum_image] - · simp only [Function.comp_apply] + · simp only [g₁, g₂,Function.comp_apply] · exact fun _ _ _ _ hxy => hf hxy theorem attach_affineCombination_coe (s : Finset P) (w : P → k) : @@ -927,7 +927,7 @@ theorem affineCombination_mem_affineSpan [Nontrivial k] {s : Finset ι} {w : ι cases' hn with i1 hi1 let w1 : ι → k := Function.update (Function.const ι 0) i1 1 have hw1 : ∑ i ∈ s, w1 i = 1 := by - simp only [Function.const_zero, Finset.sum_update_of_mem hi1, Pi.zero_apply, + simp only [w1, Function.const_zero, Finset.sum_update_of_mem hi1, Pi.zero_apply, Finset.sum_const_zero, add_zero] have hw1s : s.affineCombination k p w1 = p i1 := s.affineCombination_of_eq_one_of_eq_zero w1 p hi1 (Function.update_same _ _ _) fun _ _ hne => @@ -1057,8 +1057,8 @@ theorem mem_affineSpan_iff_eq_weightedVSubOfPoint_vadd [Nontrivial k] (p : ι let w' : ι → k := Function.update w j (1 - (s \ {j}).sum w) have h₁ : (insert j s).sum w' = 1 := by by_cases hj : j ∈ s - · simp [Finset.sum_update_of_mem hj, Finset.insert_eq_of_mem hj] - · simp [Finset.sum_insert hj, Finset.sum_update_of_not_mem hj, hj] + · simp [w', Finset.sum_update_of_mem hj, Finset.insert_eq_of_mem hj] + · simp [w', Finset.sum_insert hj, Finset.sum_update_of_not_mem hj, hj] have hww : ∀ i, i ≠ j → w i = w' i := by intro i hij simp [w', hij] diff --git a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean index 308268392107c..1adcc9da63cc8 100644 --- a/Mathlib/LinearAlgebra/AffineSpace/Independent.lean +++ b/Mathlib/LinearAlgebra/AffineSpace/Independent.lean @@ -457,14 +457,14 @@ theorem exists_nontrivial_relation_sum_zero_of_not_affine_ind {t : Finset V} simp only [Finset.weightedVSub_eq_weightedVSubOfPoint_of_sum_eq_zero _ w ((↑) : t → V) hw 0, vsub_eq_sub, Finset.weightedVSubOfPoint_apply, sub_zero] at hwt let f : ∀ x : V, x ∈ t → k := fun x hx => w ⟨x, hx⟩ - refine ⟨fun x => if hx : x ∈ t then f x hx else (0 : k), ?_, ?_, by use i; simp [hi]⟩ + refine ⟨fun x => if hx : x ∈ t then f x hx else (0 : k), ?_, ?_, by use i; simp [f, hi]⟩ on_goal 1 => suffices (∑ e ∈ t, dite (e ∈ t) (fun hx => f e hx • e) fun _ => 0) = 0 by convert this rename V => x by_cases hx : x ∈ t <;> simp [hx] all_goals - simp only [Finset.sum_dite_of_true fun _ h => h, Finset.mk_coe, hwt, hw] + simp only [f, Finset.sum_dite_of_true fun _ h => h, Finset.mk_coe, hwt, hw] variable {s : Finset ι} {w w₁ w₂ : ι → k} {p : ι → V} @@ -618,7 +618,7 @@ theorem affineIndependent_of_ne {p₁ p₂ : P} (h : p₁ ≠ p₂) : AffineInde ext fin_cases i · simp at hi - · simp + · simp [i₁] haveI : Unique { x // x ≠ (0 : Fin 2) } := ⟨⟨i₁⟩, he'⟩ apply linearIndependent_unique rw [he' default] diff --git a/Mathlib/LinearAlgebra/Basis/Basic.lean b/Mathlib/LinearAlgebra/Basis/Basic.lean index e3322e7d5c035..662046a8624b8 100644 --- a/Mathlib/LinearAlgebra/Basis/Basic.lean +++ b/Mathlib/LinearAlgebra/Basis/Basic.lean @@ -359,6 +359,10 @@ theorem isUnitSMul_apply {v : Basis ι R M} {w : ι → R} (hw : ∀ i, IsUnit ( v.isUnitSMul hw i = w i • v i := unitsSMul_apply i +theorem repr_isUnitSMul {v : Basis ι R₂ M} {w : ι → R₂} (hw : ∀ i, IsUnit (w i)) (x : M) (i : ι) : + (v.isUnitSMul hw).repr x i = (hw i).unit⁻¹ • v.repr x i := + repr_unitsSMul _ _ _ _ + section Fin /-- Let `b` be a basis for a submodule `N` of `M`. If `y : M` is linear independent of `N` diff --git a/Mathlib/LinearAlgebra/Basis/Flag.lean b/Mathlib/LinearAlgebra/Basis/Flag.lean index 4ffe11d49a060..2d138c697c2e9 100644 --- a/Mathlib/LinearAlgebra/Basis/Flag.lean +++ b/Mathlib/LinearAlgebra/Basis/Flag.lean @@ -22,7 +22,8 @@ namespace Basis section Semiring -variable {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] {n : ℕ} +variable {R M : Type*} [Semiring R] [AddCommMonoid M] [Module R M] {n : ℕ} {b : Basis (Fin n) R M} + {i j : Fin (n + 1)} /-- The subspace spanned by the first `k` vectors of the basis `b`. -/ def flag (b : Basis (Fin n) R M) (k : Fin (n + 1)) : Submodule R M := @@ -64,6 +65,11 @@ theorem isChain_range_flag (b : Basis (Fin n) R M) : IsChain (· ≤ ·) (range theorem flag_strictMono [Nontrivial R] (b : Basis (Fin n) R M) : StrictMono b.flag := Fin.strictMono_iff_lt_succ.2 fun _ ↦ by simp [flag_succ] +@[gcongr] lemma flag_le_flag (hij : i ≤ j) : b.flag i ≤ b.flag j := flag_mono _ hij + +@[gcongr] +lemma flag_lt_flag [Nontrivial R] (hij : i < j) : b.flag i < b.flag j := flag_strictMono _ hij + end Semiring section CommRing diff --git a/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean index bff969f2c534c..c003e3f2279c9 100644 --- a/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean +++ b/Mathlib/LinearAlgebra/BilinearForm/Orthogonal.lean @@ -148,7 +148,11 @@ theorem orthogonal_le (h : N ≤ L) : B.orthogonal L ≤ B.orthogonal N := fun _ theorem le_orthogonal_orthogonal (b : B.IsRefl) : N ≤ B.orthogonal (B.orthogonal N) := fun n hn _ hm => b _ _ (hm n hn) -lemma orthogonal_top (hB : B.Nondegenerate) (hB₀ : B.IsRefl) : +lemma orthogonal_top_eq_ker (hB : B.IsRefl) : + B.orthogonal ⊤ = LinearMap.ker B := by + ext; simp [LinearMap.BilinForm.IsOrtho, LinearMap.ext_iff, hB.eq_iff] + +lemma orthogonal_top_eq_bot (hB : B.Nondegenerate) (hB₀ : B.IsRefl) : B.orthogonal ⊤ = ⊥ := (Submodule.eq_bot_iff _).mpr fun _ hx ↦ hB _ fun y ↦ hB₀ _ _ <| hx y Submodule.mem_top @@ -320,7 +324,7 @@ theorem finrank_add_finrank_orthogonal (b₁ : B.IsRefl) (W : Submodule K V) : lemma finrank_orthogonal (hB : B.Nondegenerate) (hB₀ : B.IsRefl) (W : Submodule K V) : finrank K (B.orthogonal W) = finrank K V - finrank K W := by have := finrank_add_finrank_orthogonal hB₀ (W := W) - rw [B.orthogonal_top hB hB₀, inf_bot_eq, finrank_bot, add_zero] at this + rw [B.orthogonal_top_eq_bot hB hB₀, inf_bot_eq, finrank_bot, add_zero] at this have : finrank K W ≤ finrank K V := finrank_le W omega diff --git a/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean b/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean index 6df8a1d820cb3..712406dae7adc 100644 --- a/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean +++ b/Mathlib/LinearAlgebra/Charpoly/ToMatrix.lean @@ -68,7 +68,8 @@ theorem charpoly_toMatrix {ι : Type w} [DecidableEq ι] [Fintype ι] (b : Basis rw [basis_toMatrix_mul_linearMap_toMatrix_mul_basis_toMatrix] _ = det (scalar ι' X - C.mapMatrix (φ₁ P * φ₂ A' * φ₃ Q)) := by rw [reindexLinearEquiv_mul, reindexLinearEquiv_mul] - _ = det (scalar ι' X - C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by simp [φ₂] + _ = det (scalar ι' X - C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by + simp [φ₁, φ₂, φ₃, ι'] _ = det (scalar ι' X * C.mapMatrix (φ₁ P) * C.mapMatrix (φ₃ Q) - C.mapMatrix (φ₁ P) * C.mapMatrix A' * C.mapMatrix (φ₃ Q)) := by rw [Matrix.mul_assoc ((scalar ι') X), hPQ, Matrix.mul_one] diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean index 3596252e1e410..2a899d045c834 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Basic.lean @@ -207,7 +207,7 @@ theorem induction {C : CliffordAlgebra Q → Prop} -- the mapping through the subalgebra is the identity have of_id : AlgHom.id R (CliffordAlgebra Q) = s.val.comp (lift Q of) := by ext - simp [of] + simp [of, h] -- Porting note: `simp` can't apply this erw [LinearMap.codRestrict_apply] -- finding a proof is finding an element of the subalgebra diff --git a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean index d88ad52680183..65ef7c84f0abe 100644 --- a/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean +++ b/Mathlib/LinearAlgebra/CliffordAlgebra/Grading.lean @@ -99,8 +99,7 @@ theorem GradedAlgebra.lift_ι_eq (i' : ZMod 2) (x' : evenOdd Q i') : · rw [Nat.succ_eq_add_one, add_comm, Nat.cast_add, Nat.cast_one] rfl | zero => - set_option linter.deprecated false in - rw [AlgHom.map_zero] + rw [map_zero] apply Eq.symm apply DFinsupp.single_eq_zero.mpr; rfl | add x y hx hy ihx ihy => diff --git a/Mathlib/LinearAlgebra/Determinant.lean b/Mathlib/LinearAlgebra/Determinant.lean index dd5c969809a49..66160703d9068 100644 --- a/Mathlib/LinearAlgebra/Determinant.lean +++ b/Mathlib/LinearAlgebra/Determinant.lean @@ -455,13 +455,13 @@ nonrec def Basis.det : M [⋀^ι]→ₗ[R] R where cases Subsingleton.elim inst ‹_› simp only [e.toMatrix_update, LinearEquiv.map_add, Finsupp.coe_add] -- Porting note: was `exact det_update_column_add _ _ _ _` - convert det_updateColumn_add (e.toMatrix v) i (e.repr x) (e.repr y) + convert det_updateCol_add (e.toMatrix v) i (e.repr x) (e.repr y) map_update_smul' := by intro inst u i c x cases Subsingleton.elim inst ‹_› simp only [e.toMatrix_update, Algebra.id.smul_eq_mul, LinearEquiv.map_smul] -- Porting note: was `apply det_update_column_smul` - convert det_updateColumn_smul (e.toMatrix u) i c (e.repr x) + convert det_updateCol_smul (e.toMatrix u) i c (e.repr x) map_eq_zero_of_eq' := by intro v i j h hij -- Porting note: added diff --git a/Mathlib/LinearAlgebra/Dimension/Basic.lean b/Mathlib/LinearAlgebra/Dimension/Basic.lean index 16bbd326c3112..5e63e9aa3eb1a 100644 --- a/Mathlib/LinearAlgebra/Dimension/Basic.lean +++ b/Mathlib/LinearAlgebra/Dimension/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Johannes Hölzl, Sander Dahmen, Kim Morrison -/ import Mathlib.LinearAlgebra.LinearIndependent +import Mathlib.SetTheory.Cardinal.Basic /-! # Dimension of modules and vector spaces diff --git a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean index 775bb233d9c48..99dc600e166de 100644 --- a/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean +++ b/Mathlib/LinearAlgebra/Dimension/DivisionRing.lean @@ -6,7 +6,6 @@ Kim 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.RankNullity /-! @@ -22,9 +21,8 @@ For vector spaces (i.e. modules over a field), we have * `rank_quotient_add_rank_of_divisionRing`: 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. + +See also `Mathlib.LinearAlgebra.Dimension.ErdosKaplansky` for the Erdős-Kaplansky theorem. -/ @@ -178,7 +176,7 @@ theorem linearIndependent_iff_card_eq_finrank_span {ι : Type*} [Fintype ι] {b 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 [f, Set.mem_image, Set.mem_range] + simp [f, b', Set.mem_image, Set.mem_range] rw [hf] at h have hx : (x : V) ∈ span K (Set.range b) := x.property simp_rw [h] at hx @@ -217,118 +215,3 @@ noncomputable def setBasisOfTopLeSpanOfCardEqFinrank {s : Set V} [Fintype s] (_root_.trans s.toFinset_card.symm card_eq) 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 DFunLike.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 := by - refine (Subfield.cardinalMk_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 := by - 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.linearCombination_repr (bL ∘ e) - rw [Finsupp.linearCombination_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/ErdosKaplansky.lean b/Mathlib/LinearAlgebra/Dimension/ErdosKaplansky.lean new file mode 100644 index 0000000000000..a8f0c42dc1fbe --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/ErdosKaplansky.lean @@ -0,0 +1,144 @@ +/- +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, +Kim Morrison, Chris Hughes, Anne Baanen, Junyan Xu +-/ +import Mathlib.Algebra.Field.Opposite +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.LinearAlgebra.Dimension.Constructions +import Mathlib.SetTheory.Cardinal.Subfield + +/-! +# Erdős-Kaplansky theorem + +For modules over a division ring, we have + +* `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 + +variable {K : Type u} + +open Cardinal + +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 DFunLike.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 := by + refine (Subfield.cardinalMk_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 := by + 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.linearCombination_repr (bL ∘ e) + rw [Finsupp.linearCombination_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 index 6c000a000aaf9..d764634e02e3d 100644 --- a/Mathlib/LinearAlgebra/Dimension/Finite.lean +++ b/Mathlib/LinearAlgebra/Dimension/Finite.lean @@ -3,7 +3,6 @@ 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, Kim Morrison -/ -import Mathlib.Algebra.Module.Torsion import Mathlib.SetTheory.Cardinal.Cofinality import Mathlib.LinearAlgebra.FreeModule.Finite.Basic import Mathlib.LinearAlgebra.Dimension.StrongRankCondition @@ -16,7 +15,6 @@ Also contains characterization for when rank equals zero or rank equals one. -/ - noncomputable section universe u v v' w @@ -29,6 +27,19 @@ attribute [local instance] nontrivial_of_invariantBasisNumber open Basis Cardinal Function Module Set Submodule +/-- If every finite set of linearly independent vectors has cardinality at most `n`, +then the same is true for arbitrary sets of linearly independent vectors. +-/ +theorem linearIndependent_bounded_of_finset_linearIndependent_bounded {n : ℕ} + (H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) : + ∀ s : Set M, LinearIndependent R ((↑) : s → M) → #s ≤ n := by + intro s li + apply Cardinal.card_le_of + intro t + rw [← Finset.card_map (Embedding.subtype s)] + apply H + apply linearIndependent_finset_map_embedding_subtype _ li + theorem rank_le {n : ℕ} (H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) : Module.rank R M ≤ n := by @@ -88,11 +99,6 @@ theorem rank_pos [Nontrivial M] : 0 < Module.rank R M := end -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] - variable (R M) /-- See `rank_subsingleton` that assumes `Subsingleton R` instead. -/ @@ -418,13 +424,6 @@ theorem Module.finrank_eq_zero_iff : rw [← rank_eq_zero_iff (R := R), ← finrank_eq_rank] norm_cast -/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/ -theorem Module.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 := by - rw [← rank_eq_zero_iff_isTorsion (R := R), ← finrank_eq_rank] - norm_cast - /-- A finite dimensional space has zero `finrank` iff it is a subsingleton. This is the `finrank` version of `rank_zero_iff`. -/ theorem Module.finrank_zero_iff [NoZeroSMulDivisors R M] : diff --git a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean index cf3c16a79daa0..48fd4277e7c4f 100644 --- a/Mathlib/LinearAlgebra/Dimension/RankNullity.lean +++ b/Mathlib/LinearAlgebra/Dimension/RankNullity.lean @@ -209,16 +209,17 @@ lemma Submodule.finrank_quotient [Module.Finite R M] {S : Type*} [Ring S] [SMul rw [← (N.restrictScalars R).finrank_quotient_add_finrank] exact Nat.eq_sub_of_add_eq rfl -lemma Submodule.disjoint_ker_of_finrank_eq [NoZeroSMulDivisors R M] {N : Type*} [AddCommGroup N] +lemma Submodule.disjoint_ker_of_finrank_le [NoZeroSMulDivisors R M] {N : Type*} [AddCommGroup N] [Module R N] {L : Submodule R M} [Module.Finite R L] (f : M →ₗ[R] N) - (h : finrank R (L.map f) = finrank R L) : + (h : finrank R L ≤ finrank R (L.map f)) : Disjoint L (LinearMap.ker f) := by refine disjoint_iff.mpr <| LinearMap.injective_domRestrict_iff.mp <| LinearMap.ker_eq_bot.mp <| Submodule.rank_eq_zero.mp ?_ rw [← Submodule.finrank_eq_rank, Nat.cast_eq_zero] rw [← LinearMap.range_domRestrict] at h have := (LinearMap.ker (f.domRestrict L)).finrank_quotient_add_finrank - rwa [LinearEquiv.finrank_eq (f.domRestrict L).quotKerEquivRange, h, Nat.add_eq_left] at this + rw [LinearEquiv.finrank_eq (f.domRestrict L).quotKerEquivRange] at this + omega end Finrank diff --git a/Mathlib/LinearAlgebra/Dimension/Torsion.lean b/Mathlib/LinearAlgebra/Dimension/Torsion/Basic.lean similarity index 100% rename from Mathlib/LinearAlgebra/Dimension/Torsion.lean rename to Mathlib/LinearAlgebra/Dimension/Torsion/Basic.lean diff --git a/Mathlib/LinearAlgebra/Dimension/Torsion/Finite.lean b/Mathlib/LinearAlgebra/Dimension/Torsion/Finite.lean new file mode 100644 index 0000000000000..3271bdb4aa7c9 --- /dev/null +++ b/Mathlib/LinearAlgebra/Dimension/Torsion/Finite.lean @@ -0,0 +1,24 @@ +/- +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, Kim Morrison +-/ +import Mathlib.Algebra.Module.Torsion +import Mathlib.LinearAlgebra.Dimension.Finite + +/-! +# Results relating rank and torsion. + +-/ + +variable {R M : Type*} [CommRing R] [IsDomain R] [AddCommGroup M] [Module R M] + +lemma rank_eq_zero_iff_isTorsion: Module.rank R M = 0 ↔ Module.IsTorsion R M := by + rw [Module.IsTorsion, rank_eq_zero_iff] + simp [mem_nonZeroDivisors_iff_ne_zero] + +/-- The `StrongRankCondition` is automatic. See `commRing_strongRankCondition`. -/ +theorem Module.finrank_eq_zero_iff_isTorsion [StrongRankCondition R] [Module.Finite R M] : + finrank R M = 0 ↔ Module.IsTorsion R M := by + rw [← rank_eq_zero_iff_isTorsion (R := R), ← finrank_eq_rank] + norm_cast diff --git a/Mathlib/LinearAlgebra/Dual.lean b/Mathlib/LinearAlgebra/Dual.lean index 3870b51c3d7f0..398f24af5888d 100644 --- a/Mathlib/LinearAlgebra/Dual.lean +++ b/Mathlib/LinearAlgebra/Dual.lean @@ -11,6 +11,7 @@ import Mathlib.LinearAlgebra.SesquilinearForm import Mathlib.RingTheory.Finiteness.Projective import Mathlib.RingTheory.LocalRing.Basic import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.LinearAlgebra.Dimension.ErdosKaplansky /-! # Dual vector spaces @@ -802,7 +803,8 @@ theorem _root_.mem_span_of_iInf_ker_le_ker [Finite ι] {L : ι → E →ₗ[𝕜 rw [← p.liftQ_mkQ K h] ext x convert LinearMap.congr_fun hK' (p.mkQ x) - simp only [coeFn_sum, Finset.sum_apply, smul_apply, coe_comp, Function.comp_apply, smul_eq_mul] + simp only [L',coeFn_sum, Finset.sum_apply, smul_apply, coe_comp, Function.comp_apply, + smul_eq_mul] end Submodule @@ -1246,6 +1248,11 @@ noncomputable def quotEquivAnnihilator (W : Subspace K V) : (V ⧸ W) ≃ₗ[K] open Module +theorem finrank_add_finrank_dualAnnihilator_eq (W : Subspace K V) : + finrank K W + finrank K W.dualAnnihilator = finrank K V := by + rw [← W.quotEquivAnnihilator.finrank_eq (M₂ := dualAnnihilator W), + add_comm, Submodule.finrank_quotient_add_finrank] + @[simp] theorem finrank_dualCoannihilator_eq {Φ : Subspace K (Module.Dual K V)} : finrank K Φ.dualCoannihilator = finrank K Φ.dualAnnihilator := by @@ -1254,12 +1261,7 @@ theorem finrank_dualCoannihilator_eq {Φ : Subspace K (Module.Dual K V)} : theorem finrank_add_finrank_dualCoannihilator_eq (W : Subspace K (Module.Dual K V)) : finrank K W + finrank K W.dualCoannihilator = finrank K V := by - rw [finrank_dualCoannihilator_eq] - -- Porting note: LinearEquiv.finrank_eq needs help - let equiv := W.quotEquivAnnihilator - have eq := LinearEquiv.finrank_eq (R := K) (M := (Module.Dual K V) ⧸ W) - (M₂ := { x // x ∈ dualAnnihilator W }) equiv - rw [eq.symm, add_comm, Submodule.finrank_quotient_add_finrank, Subspace.dual_finrank_eq] + rw [finrank_dualCoannihilator_eq, finrank_add_finrank_dualAnnihilator_eq, dual_finrank_eq] end @@ -1895,4 +1897,4 @@ noncomputable def dualDistribEquiv : Dual R M ⊗[R] Dual R N ≃ₗ[R] Dual R ( end TensorProduct -set_option linter.style.longFile 1900 +set_option linter.style.longFile 2100 diff --git a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean index 3003ced8d18b7..5aeea273a0985 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Basic.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Basic.lean @@ -7,7 +7,10 @@ import Mathlib.Algebra.Algebra.Spectrum import Mathlib.Algebra.Module.LinearMap.Basic import Mathlib.LinearAlgebra.GeneralLinearGroup import Mathlib.LinearAlgebra.FiniteDimensional +import Mathlib.RingTheory.Nilpotent.Defs +import Mathlib.RingTheory.Nilpotent.Lemmas import Mathlib.RingTheory.Nilpotent.Basic +import Mathlib.Tactic.Peel /-! # Eigenvectors and eigenvalues diff --git a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean index 76112cc06a755..6a90c71055221 100644 --- a/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean +++ b/Mathlib/LinearAlgebra/Eigenspace/Triangularizable.lean @@ -134,7 +134,7 @@ theorem iSup_maxGenEigenspace_eq_top [IsAlgClosed K] [FiniteDimensional K V] (f -- Since the dimensions of `ER` and `ES` add up to the dimension of `V`, it follows that the -- span of all generalized eigenvectors is all of `V`. show ⨆ (μ : K), f.maxGenEigenspace μ = ⊤ - rw [← top_le_iff, ← Submodule.eq_top_of_disjoint ER ES h_dim_add h_disjoint] + rw [← top_le_iff, ← Submodule.eq_top_of_disjoint ER ES h_dim_add.ge h_disjoint] apply sup_le hER hES -- Lemma 8.21 of [axler2015] diff --git a/Mathlib/LinearAlgebra/ExteriorPower/Basic.lean b/Mathlib/LinearAlgebra/ExteriorPower/Basic.lean new file mode 100644 index 0000000000000..e02ccb29fa8ea --- /dev/null +++ b/Mathlib/LinearAlgebra/ExteriorPower/Basic.lean @@ -0,0 +1,201 @@ +/- +Copyright (c) 2024 Sophie Morel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sophie Morel, Joël Riou +-/ +import Mathlib.Algebra.Module.Presentation.Basic +import Mathlib.LinearAlgebra.ExteriorAlgebra.OfAlternating + +/-! +# Exterior powers + +We study the exterior powers of a module `M` over a commutative ring `R`. + +## Definitions + +* `exteriorPower.ιMulti` is the canonical alternating map on `M` with values in `⋀[R]^n M`. + +* `exteriorPower.presentation R n M` is the standard presentation of the `R`-module `⋀[R]^n M`. + +## Theorems +* `ιMulti_span`: The image of `exteriorPower.ιMulti` spans `⋀[R]^n M`. + +* We construct `exteriorPower.alternatingMapLinearEquiv` which +expresses the universal property of the exterior power as a +linear equivalence `(M [⋀^Fin n]→ₗ[R] N) ≃ₗ[R] ⋀[R]^n M →ₗ[R] N` between +alternating maps and linear maps from the exterior power. + +-/ + +open scoped TensorProduct + +universe u v uM uN uN' uN'' uE uF + +variable (R : Type u) [CommRing R] (n : ℕ) {M N N' : Type*} + [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + [AddCommGroup N'] [Module R N'] + +namespace exteriorPower + +open Function + +/-! The canonical alternating map from `Fin n → M` to `⋀[R]^n M`. -/ + +/-- `exteriorAlgebra.ιMulti` is the alternating map from `Fin n → M` to `⋀[r]^n M` +induced by `exteriorAlgebra.ιMulti`, i.e. sending a family of vectors `m : Fin n → M` to the +product of its entries. -/ +def ιMulti : M [⋀^Fin n]→ₗ[R] (⋀[R]^n M) := + (ExteriorAlgebra.ιMulti R n).codRestrict (⋀[R]^n M) fun _ => + ExteriorAlgebra.ιMulti_range R n <| Set.mem_range_self _ + +@[simp] lemma ιMulti_apply_coe (a : Fin n → M) : ιMulti R n a = ExteriorAlgebra.ιMulti R n a := rfl + +variable (M) +/-- The image of `ExteriorAlgebra.ιMulti R n` spans the `n`th exterior power. Variant of +`ExteriorAlgebra.ιMulti_span_fixedDegree`, useful in rewrites. -/ +lemma ιMulti_span_fixedDegree : + Submodule.span R (Set.range (ExteriorAlgebra.ιMulti R n)) = ⋀[R]^n M := + ExteriorAlgebra.ιMulti_span_fixedDegree R n + +/-- The image of `exteriorPower.ιMulti` spans `⋀[R]^n M`. -/ +lemma ιMulti_span : + Submodule.span R (Set.range (ιMulti R n)) = (⊤ : Submodule R (⋀[R]^n M)) := by + apply LinearMap.map_injective (Submodule.ker_subtype (⋀[R]^n M)) + rw [LinearMap.map_span, ← Set.image_univ, Set.image_image] + simp only [Submodule.coe_subtype, ιMulti_apply_coe, Set.image_univ, Submodule.map_top, + Submodule.range_subtype] + exact ExteriorAlgebra.ιMulti_span_fixedDegree R n + +namespace presentation + +/-- The index type for the relations in the standard presentation of `⋀[R]^n M`, +in the particular case `ι` is `Fin n`. -/ +inductive Rels (ι : Type*) (M : Type*) + | add (m : ι → M) (i : ι) (x y : M) + | smul (m : ι → M) (i : ι) (r : R) (x : M) + | alt (m : ι → M) (i j : ι) (hm : m i = m j) (hij : i ≠ j) + +/-- The relations in the standard presentation of `⋀[R]^n M` with generators and relations. -/ +@[simps] +noncomputable def relations (ι : Type*) [DecidableEq ι] (M : Type*) + [AddCommGroup M] [Module R M] : + Module.Relations R where + G := ι → M + R := Rels R ι M + relation r := match r with + | .add m i x y => Finsupp.single (update m i x) 1 + + Finsupp.single (update m i y) 1 - + Finsupp.single (update m i (x + y)) 1 + | .smul m i r x => Finsupp.single (update m i (r • x)) 1 - + r • Finsupp.single (update m i x) 1 + | .alt m _ _ _ _ => Finsupp.single m 1 + +variable {R} in +/-- The solutions in a module `N` to the linear equations +given by `exteriorPower.relations R ι M` identify to alternating maps to `N`. -/ +@[simps!] +def relationsSolutionEquiv {ι : Type*} [DecidableEq ι] {M : Type*} + [AddCommGroup M] [Module R M] : + (relations R ι M).Solution N ≃ AlternatingMap R M N ι where + toFun s := + { toFun := fun m ↦ s.var m + map_update_add' := fun m i x y ↦ by + have := s.linearCombination_var_relation (.add m i x y) + dsimp at this ⊢ + rw [map_sub, map_add, Finsupp.linearCombination_single, one_smul, + Finsupp.linearCombination_single, one_smul, + Finsupp.linearCombination_single, one_smul, sub_eq_zero] at this + convert this.symm -- `convert` is necessary due to the implementation of `MultilinearMap` + map_update_smul' := fun m i r x ↦ by + have := s.linearCombination_var_relation (.smul m i r x) + dsimp at this ⊢ + rw [Finsupp.smul_single, smul_eq_mul, mul_one, map_sub, + Finsupp.linearCombination_single, one_smul, + Finsupp.linearCombination_single, sub_eq_zero] at this + convert this + map_eq_zero_of_eq' := fun v i j hm hij ↦ + by simpa using s.linearCombination_var_relation (.alt v i j hm hij) } + invFun f := + { var := fun m ↦ f m + linearCombination_var_relation := by + rintro (⟨m, i, x, y⟩ | ⟨m, i, r, x⟩ | ⟨v, i, j, hm, hij⟩) + · simp + · simp + · simpa using f.map_eq_zero_of_eq v hm hij } + left_inv _ := rfl + right_inv _ := rfl + +/-- The universal property of the exterior power. -/ +def isPresentationCore : + (relationsSolutionEquiv.symm (ιMulti R n (M := M))).IsPresentationCore where + desc s := LinearMap.comp (ExteriorAlgebra.liftAlternating + (Function.update 0 n (relationsSolutionEquiv s))) (Submodule.subtype _) + postcomp_desc s := by aesop + postcomp_injective {N _ _ f f' h} := by + rw [Submodule.linearMap_eq_iff_of_span_eq_top _ _ (ιMulti_span R n M)] + rintro ⟨_, ⟨f, rfl⟩⟩ + exact Module.Relations.Solution.congr_var h f + +end presentation + +/-- The standard presentation of the `R`-module `⋀[R]^n M`. -/ +@[simps! G R relation var] +noncomputable def presentation : Module.Presentation R (⋀[R]^n M) := + .ofIsPresentation (presentation.isPresentationCore R n M).isPresentation + +variable {R M n} + +/-- Two linear maps on `⋀[R]^n M` that agree on the image of `exteriorPower.ιMulti` +are equal. -/ +@[ext] +lemma linearMap_ext {f : ⋀[R]^n M →ₗ[R] N} {g : ⋀[R]^n M →ₗ[R] N} + (heq : f.compAlternatingMap (ιMulti R n) = g.compAlternatingMap (ιMulti R n)) : f = g := + (presentation R n M).postcomp_injective (by ext f; apply DFunLike.congr_fun heq ) + +/-- The linear equivalence between `n`-fold alternating maps from `M` to `N` and linear maps from +`⋀[R]^n M` to `N`: this is the universal property of the `n`th exterior power of `M`. -/ +noncomputable def alternatingMapLinearEquiv : (M [⋀^Fin n]→ₗ[R] N) ≃ₗ[R] ⋀[R]^n M →ₗ[R] N := + LinearEquiv.symm + (Equiv.toLinearEquiv + ((presentation R n M).linearMapEquiv.trans presentation.relationsSolutionEquiv) + { map_add := fun _ _ => rfl + map_smul := fun _ _ => rfl }) + +@[simp] +lemma alternatingMapLinearEquiv_comp_ιMulti (f : M [⋀^Fin n]→ₗ[R] N) : + (alternatingMapLinearEquiv f).compAlternatingMap (ιMulti R n) = f := by + obtain ⟨φ, rfl⟩ := alternatingMapLinearEquiv.symm.surjective f + dsimp [alternatingMapLinearEquiv] + simp only [LinearEquiv.symm_apply_apply] + rfl + +@[simp] +lemma alternatingMapLinearEquiv_apply_ιMulti (f : M [⋀^Fin n]→ₗ[R] N) (a : Fin n → M) : + alternatingMapLinearEquiv f (ιMulti R n a) = f a := + DFunLike.congr_fun (alternatingMapLinearEquiv_comp_ιMulti f) a + +@[simp] +lemma alternatingMapLinearEquiv_symm_apply (F : ⋀[R]^n M →ₗ[R] N) (m : Fin n → M) : + alternatingMapLinearEquiv.symm F m = F.compAlternatingMap (ιMulti R n) m := by + obtain ⟨f, rfl⟩ := alternatingMapLinearEquiv.surjective F + simp only [LinearEquiv.symm_apply_apply, alternatingMapLinearEquiv_comp_ιMulti] + +@[simp] +lemma alternatingMapLinearEquiv_ιMulti : + alternatingMapLinearEquiv (ιMulti R n (M := M)) = LinearMap.id := by + ext + simp only [alternatingMapLinearEquiv_comp_ιMulti, ιMulti_apply_coe, + LinearMap.compAlternatingMap_apply, LinearMap.id_coe, id_eq] + +/-- If `f` is an alternating map from `M` to `N`, +`alternatingMapLinearEquiv f` is the corresponding linear map from `⋀[R]^n M` to `N`, +and if `g` is a linear map from `N` to `N'`, then +the alternating map `g.compAlternatingMap f` from `M` to `N'` corresponds to the linear +map `g.comp (alternatingMapLinearEquiv f)` on `⋀[R]^n M`. -/ +lemma alternatingMapLinearEquiv_comp (g : N →ₗ[R] N') (f : M [⋀^Fin n]→ₗ[R] N) : + alternatingMapLinearEquiv (g.compAlternatingMap f) = g.comp (alternatingMapLinearEquiv f) := by + ext + simp only [alternatingMapLinearEquiv_comp_ιMulti, LinearMap.compAlternatingMap_apply, + LinearMap.coe_comp, comp_apply, alternatingMapLinearEquiv_apply_ιMulti] + +end exteriorPower diff --git a/Mathlib/LinearAlgebra/FiniteDimensional.lean b/Mathlib/LinearAlgebra/FiniteDimensional.lean index 3b375180e50b1..3795257b53d17 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional.lean @@ -6,6 +6,7 @@ Authors: Chris Hughes import Mathlib.LinearAlgebra.FiniteDimensional.Defs import Mathlib.LinearAlgebra.Dimension.FreeAndStrongRankCondition import Mathlib.LinearAlgebra.Dimension.DivisionRing +import Mathlib.Tactic.IntervalCases /-! # Finite dimensional vector spaces @@ -18,6 +19,9 @@ Definitions and results that require fewer imports are in -/ +assert_not_exists Monoid.exponent +assert_not_exists Module.IsTorsion + universe u v v' @@ -54,22 +58,29 @@ theorem finrank_add_le_finrank_add_finrank (s t : Submodule K V) [FiniteDimensio rw [← finrank_sup_add_finrank_inf_eq] exact self_le_add_right _ _ +theorem finrank_add_finrank_le_of_disjoint [FiniteDimensional K V] + {s t : Submodule K V} (hdisjoint : Disjoint s t) : + finrank K s + finrank K t ≤ finrank K V := by + rw [← Submodule.finrank_sup_add_finrank_inf_eq s t, hdisjoint.eq_bot, finrank_bot, add_zero] + exact Submodule.finrank_le _ + theorem eq_top_of_disjoint [FiniteDimensional K V] (s t : Submodule K V) - (hdim : finrank K s + finrank K t = finrank K V) (hdisjoint : Disjoint s t) : s ⊔ t = ⊤ := by + (hdim : finrank K V ≤ finrank K s + finrank K t) (hdisjoint : Disjoint s t) : s ⊔ t = ⊤ := by have h_finrank_inf : finrank K ↑(s ⊓ t) = 0 := by rw [disjoint_iff_inf_le, le_bot_iff] at hdisjoint rw [hdisjoint, finrank_bot] apply eq_top_of_finrank_eq - rw [← hdim] + replace hdim : finrank K V = finrank K s + finrank K t := + le_antisymm hdim (finrank_add_finrank_le_of_disjoint hdisjoint) + rw [hdim] convert s.finrank_sup_add_finrank_inf_eq t rw [h_finrank_inf] rfl -theorem finrank_add_finrank_le_of_disjoint [FiniteDimensional K V] - {s t : Submodule K V} (hdisjoint : Disjoint s t) : - finrank K s + finrank K t ≤ finrank K V := by - rw [← Submodule.finrank_sup_add_finrank_inf_eq s t, hdisjoint.eq_bot, finrank_bot, add_zero] - exact Submodule.finrank_le _ +theorem isCompl_iff_disjoint [FiniteDimensional K V] (s t : Submodule K V) + (hdim : finrank K V ≤ finrank K s + finrank K t) : + IsCompl s t ↔ Disjoint s t := + ⟨fun h ↦ h.1, fun h ↦ ⟨h, codisjoint_iff.mpr <| eq_top_of_disjoint s t hdim h⟩⟩ end DivisionRing diff --git a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean index ccf5f3bda0fb2..16ac3a373d3e2 100644 --- a/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean +++ b/Mathlib/LinearAlgebra/FiniteDimensional/Defs.lean @@ -758,17 +758,6 @@ open Module variable {F E : Type*} [Field F] [Ring E] [Algebra F E] -/- -porting note: -Some of the lemmas in this section can be made faster by adding these short-cut instances -```lean4 -instance (S : Subalgebra F E) : AddCommMonoid { x // x ∈ S } := inferInstance -instance (S : Subalgebra F E) : AddCommGroup { x // x ∈ S } := inferInstance -``` -However, this approach doesn't scale very well, so we should consider holding off on adding -them until we have no choice. --/ - /-- A `Subalgebra` is `FiniteDimensional` iff it is `FiniteDimensional` as a submodule. -/ theorem Subalgebra.finiteDimensional_toSubmodule {S : Subalgebra F E} : FiniteDimensional F (Subalgebra.toSubmodule S) ↔ FiniteDimensional F S := diff --git a/Mathlib/LinearAlgebra/Finsupp/VectorSpace.lean b/Mathlib/LinearAlgebra/Finsupp/VectorSpace.lean index 55e82e68d64d0..8fd119ba66b51 100644 --- a/Mathlib/LinearAlgebra/Finsupp/VectorSpace.lean +++ b/Mathlib/LinearAlgebra/Finsupp/VectorSpace.lean @@ -19,7 +19,6 @@ This file contains results on the `R`-module structure on functions of finite su noncomputable section open Set LinearMap Submodule -open scoped Cardinal universe u v w diff --git a/Mathlib/LinearAlgebra/FreeModule/Basic.lean b/Mathlib/LinearAlgebra/FreeModule/Basic.lean index 99e69913af94b..78dc32b0099f9 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Basic.lean @@ -7,6 +7,7 @@ import Mathlib.Data.Finsupp.Fintype import Mathlib.Data.Matrix.Defs import Mathlib.LinearAlgebra.Basis.Basic import Mathlib.LinearAlgebra.TensorProduct.Basis +import Mathlib.Logic.Small.Basic /-! # Free modules @@ -37,6 +38,10 @@ variable [Semiring R] [AddCommMonoid M] [Module R M] class Module.Free : Prop where exists_basis : Nonempty <| (I : Type v) × Basis I R M +theorem Module.free_iff_set : Module.Free R M ↔ ∃ S : Set M, Nonempty (Basis S R M) := + ⟨fun h => ⟨Set.range h.exists_basis.some.2, ⟨Basis.reindexRange h.exists_basis.some.2⟩⟩, + fun ⟨S, hS⟩ => ⟨nonempty_sigma.2 ⟨S, hS⟩⟩⟩ + /-- If `M` fits in universe `w`, then freeness is equivalent to existence of a basis in that universe. @@ -49,10 +54,6 @@ theorem Module.free_def [Small.{w,v} M] : ⟨(Basis.reindexRange h.exists_basis.some.2).reindex (equivShrink _)⟩⟩, fun h => ⟨(nonempty_sigma.2 h).map fun ⟨_, b⟩ => ⟨Set.range b, b.reindexRange⟩⟩⟩ -theorem Module.free_iff_set : Module.Free R M ↔ ∃ S : Set M, Nonempty (Basis S R M) := - ⟨fun h => ⟨Set.range h.exists_basis.some.2, ⟨Basis.reindexRange h.exists_basis.some.2⟩⟩, - fun ⟨S, hS⟩ => ⟨nonempty_sigma.2 ⟨S, hS⟩⟩⟩ - variable {R M} theorem Module.Free.of_basis {ι : Type w} (b : Basis ι R M) : Module.Free R M := diff --git a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean index 218d9eb918e6a..bc49290326666 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Finite/Matrix.lean @@ -5,6 +5,7 @@ Authors: Riccardo Brasca -/ import Mathlib.LinearAlgebra.Dimension.LinearMap import Mathlib.LinearAlgebra.FreeModule.StrongRankCondition +import Mathlib.LinearAlgebra.Matrix.ToLin /-! # Finite and free modules using matrices diff --git a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean index e4b38dca36171..7e5fc7690e990 100644 --- a/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean +++ b/Mathlib/LinearAlgebra/FreeModule/IdealQuotient.lean @@ -41,9 +41,7 @@ noncomputable def quotientEquivPiSpan (I : Ideal S) (b : Basis ι R S) (hI : I have ab_eq := I.selfBasis_def b hI have mem_I_iff : ∀ x, x ∈ I ↔ ∀ i, a i ∣ b'.repr x i := by intro x - -- Porting note: these lines used to be `simp_rw [ab.mem_ideal_iff', ab_eq]` - rw [ab.mem_ideal_iff'] - simp_rw [ab_eq] + simp_rw [ab.mem_ideal_iff', ab, ab_eq] have : ∀ (c : ι → R) (i), b'.repr (∑ j : ι, c j • a j • b' j) i = a i * c i := by intro c i simp only [← MulAction.mul_smul, b'.repr_sum_self, mul_comm] diff --git a/Mathlib/LinearAlgebra/FreeModule/Norm.lean b/Mathlib/LinearAlgebra/FreeModule/Norm.lean index fb5d577bae4c0..29317643488c0 100644 --- a/Mathlib/LinearAlgebra/FreeModule/Norm.lean +++ b/Mathlib/LinearAlgebra/FreeModule/Norm.lean @@ -6,6 +6,7 @@ Authors: Junyan Xu import Mathlib.LinearAlgebra.FreeModule.IdealQuotient import Mathlib.RingTheory.Norm.Defs import Mathlib.RingTheory.AdjoinRoot +import Mathlib.LinearAlgebra.Dual /-! # Norms on free modules over principal ideal domains diff --git a/Mathlib/LinearAlgebra/FreeProduct/Basic.lean b/Mathlib/LinearAlgebra/FreeProduct/Basic.lean index bfa28160ab5c3..a6d1297916a19 100644 --- a/Mathlib/LinearAlgebra/FreeProduct/Basic.lean +++ b/Mathlib/LinearAlgebra/FreeProduct/Basic.lean @@ -68,7 +68,7 @@ universe uS uA uB then their quotients are also `R`-equivalent. (Special case of the third isomorphism theorem.)-/ -def algEquiv_quot_algEquiv +def algEquivQuotAlgEquiv {R : Type u} [CommSemiring R] {A B : Type v} [Semiring A] [Semiring B] [Algebra R A] [Algebra R B] (f : A ≃ₐ[R] B) (rel : A → A → Prop) : RingQuot rel ≃ₐ[R] RingQuot (rel on f.symm) := @@ -83,16 +83,20 @@ def algEquiv_quot_algEquiv fun x y h ↦ by apply RingQuot.mkAlgHom_rel; simpa⟩)) (by ext b; simp) (by ext a; simp) +@[deprecated (since := "2024-12-07")] alias algEquiv_quot_algEquiv := algEquivQuotAlgEquiv + /--If two (semi)rings are equivalent and their quotients by a relation `rel` are defined, then their quotients are also equivalent. (Special case of `algEquiv_quot_algEquiv` when `R = ℕ`, which in turn is a special case of the third isomorphism theorem.)-/ -def equiv_quot_equiv {A B : Type v} [Semiring A] [Semiring B] (f : A ≃+* B) (rel : A → A → Prop) : +def equivQuotEquiv {A B : Type v} [Semiring A] [Semiring B] (f : A ≃+* B) (rel : A → A → Prop) : RingQuot rel ≃+* RingQuot (rel on f.symm) := let f_alg : A ≃ₐ[ℕ] B := AlgEquiv.ofRingEquiv (f := f) (fun n ↦ by simp) - algEquiv_quot_algEquiv f_alg rel |>.toRingEquiv + algEquivQuotAlgEquiv f_alg rel |>.toRingEquiv + +@[deprecated (since := "2024-12-07")] alias equiv_quot_equiv := equivQuotEquiv end RingQuot @@ -143,11 +147,14 @@ theorem rel_id (i : I) : rel R A (ι R <| lof R I A i 1) 1 := rel.id @[reducible] def _root_.LinearAlgebra.FreeProduct := RingQuot <| FreeProduct.rel R A /--The free product of the collection of `R`-algebras `A i`, as a quotient of `PowerAlgebra R A`-/ -@[reducible] def _root_.LinearAlgebra.FreeProduct_ofPowers := RingQuot <| FreeProduct.rel' R A +@[reducible] def _root_.LinearAlgebra.FreeProductOfPowers := RingQuot <| FreeProduct.rel' R A + +@[deprecated (since := "2024-12-07")] +alias _root_.LinearAlgebra.FreeProduct_ofPowers := LinearAlgebra.FreeProductOfPowers /--The `R`-algebra equivalence relating `FreeProduct` and `FreeProduct_ofPowers`-/ -noncomputable def equivPowerAlgebra : FreeProduct_ofPowers R A ≃ₐ[R] FreeProduct R A := - RingQuot.algEquiv_quot_algEquiv +noncomputable def equivPowerAlgebra : FreeProductOfPowers R A ≃ₐ[R] FreeProduct R A := + RingQuot.algEquivQuotAlgEquiv (FreeProduct.powerAlgebra_equiv_freeAlgebra R A |>.symm) (FreeProduct.rel R A) |>.symm diff --git a/Mathlib/LinearAlgebra/Goursat.lean b/Mathlib/LinearAlgebra/Goursat.lean new file mode 100644 index 0000000000000..0316c6952d5d5 --- /dev/null +++ b/Mathlib/LinearAlgebra/Goursat.lean @@ -0,0 +1,137 @@ +/- +Copyright (c) 2024 David Loeffler. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: David Loeffler +-/ +import Mathlib.GroupTheory.Goursat +import Mathlib.LinearAlgebra.Prod +import Mathlib.LinearAlgebra.Quotient.Basic + +/-! +# Goursat's lemma for submodules + +Let `M, N` be modules over a ring `R`. If `L` is a submodule of `M × N` which projects fully on +to both factors, then there exist submodules `M' ≤ M` and `N' ≤ N` such that `M' × N' ≤ L` and the +image of `L` in `(M ⧸ M') × (N ⧸ N')` is the graph of an isomorphism `M ⧸ M' ≃ₗ[R] N ⧸ N'`. +Equivalently, `L` is equal to the preimage in `M × N` of the graph of this isomorphism +`M ⧸ M' ≃ₗ[R] N ⧸ N'`. + +`M'` and `N'` can be explicitly constructed as `Submodule.goursatFst L` and `Submodule.goursatSnd L` +respectively. +-/ + +open Function Set LinearMap + +namespace Submodule +variable {R M N : Type*} [Ring R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + {L : Submodule R (M × N)} + (hL₁ : Surjective (Prod.fst ∘ L.subtype)) (hL₂ : Surjective (Prod.snd ∘ L.subtype)) + +variable (L) in +/-- For `L` a submodule of `M × N`, `L.goursatFst` is the kernel of the projection map `L → N`, +considered as a submodule of `M`. + +This is the first submodule appearing in Goursat's lemma. See `Subgroup.goursat`. -/ +def goursatFst : Submodule R M := + ((LinearMap.snd R M N).comp L.subtype).ker.map ((LinearMap.fst R M N).comp L.subtype) + + +variable (L) in +/-- For `L` a subgroup of `M × N`, `L.goursatSnd` is the kernel of the projection map `L → M`, +considered as a subgroup of `N`. + +This is the second subgroup appearing in Goursat's lemma. See `Subgroup.goursat`. -/ +def goursatSnd : Submodule R N := + ((LinearMap.fst R M N).comp L.subtype).ker.map ((LinearMap.snd R M N).comp L.subtype) + +lemma goursatFst_toAddSubgroup : + (goursatFst L).toAddSubgroup = L.toAddSubgroup.goursatFst := by + ext x + simp [mem_toAddSubgroup, goursatFst, AddSubgroup.mem_goursatFst] + +lemma goursatSnd_toAddSubgroup : + (goursatSnd L).toAddSubgroup = L.toAddSubgroup.goursatSnd := by + ext x + simp [mem_toAddSubgroup, goursatSnd, AddSubgroup.mem_goursatSnd] + +variable (L) in +lemma goursatFst_prod_goursatSnd_le : L.goursatFst.prod L.goursatSnd ≤ L := by + simpa only [← toAddSubgroup_le, goursatFst_toAddSubgroup, goursatSnd_toAddSubgroup] + using L.toAddSubgroup.goursatFst_prod_goursatSnd_le + +include hL₁ hL₂ in +/-- **Goursat's lemma** for a submodule of a product with surjective projections. + +If `L` is a submodule of `M × N` which projects fully on both factors, then there exist submodules +`M' ≤ M` and `N' ≤ N` such that `M' × N' ≤ L` and the image of `L` in `(M ⧸ M') × (N ⧸ N')` is the +graph of an isomorphism of `R`-modules `(M ⧸ M') ≃ (N ⧸ N')`. + +`M` and `N` can be explicitly constructed as `L.goursatFst` and `L.goursatSnd` respectively. -/ +lemma goursat_surjective : ∃ e : (M ⧸ L.goursatFst) ≃ₗ[R] N ⧸ L.goursatSnd, + LinearMap.range ((L.goursatFst.mkQ.prodMap L.goursatSnd.mkQ).comp L.subtype) = e.graph := by + -- apply add-group result + obtain ⟨(e : M ⧸ L.goursatFst ≃+ N ⧸ L.goursatSnd), he⟩ := + L.toAddSubgroup.goursat_surjective hL₁ hL₂ + -- check R-linearity of the map + have (r : R) (x : M ⧸ L.goursatFst) : e (r • x) = r • e x := by + show (r • x, r • e x) ∈ e.toAddMonoidHom.graph + rw [← he, ← Prod.smul_mk] + have : (x, e x) ∈ e.toAddMonoidHom.graph := rfl + rw [← he, AddMonoidHom.mem_range] at this + rcases this with ⟨⟨l, hl⟩, hl'⟩ + use ⟨r • l, L.smul_mem r hl⟩ + rw [← hl'] + rfl + -- define the map as an R-linear equiv + use { e with map_smul' := this } + rw [← toAddSubgroup_injective.eq_iff] + convert he using 1 + ext v + rw [mem_toAddSubgroup, mem_graph_iff, Eq.comm] + rfl + +/-- **Goursat's lemma** for an arbitrary submodule of a product. + +If `L` is a submodule of `M × N`, then there exist submodules `M'' ≤ M' ≤ M` and `N'' ≤ N' ≤ N` such +that `L ≤ M' × N'`, and `L` is (the image in `M × N` of) the preimage of the graph of an `R`-linear +isomorphism `M' ⧸ M'' ≃ N' ⧸ N''`. -/ +lemma goursat : ∃ (M' : Submodule R M) (N' : Submodule R N) (M'' : Submodule R M') + (N'' : Submodule R N') (e : (M' ⧸ M'') ≃ₗ[R] N' ⧸ N''), + L = (e.graph.comap <| M''.mkQ.prodMap N''.mkQ).map (M'.subtype.prodMap N'.subtype) := by + let M' := L.map (LinearMap.fst ..) + let N' := L.map (LinearMap.snd ..) + let P : L →ₗ[R] M' := (LinearMap.fst ..).submoduleMap L + let Q : L →ₗ[R] N' := (LinearMap.snd ..).submoduleMap L + let L' : Submodule R (M' × N') := LinearMap.range (P.prod Q) + have hL₁' : Surjective (Prod.fst ∘ L'.subtype) := by + simp only [← coe_fst (R := R), ← coe_comp, ← range_eq_top, LinearMap.range_comp, range_subtype] + simpa only [L', ← LinearMap.range_comp, fst_prod, range_eq_top] using + (LinearMap.fst ..).submoduleMap_surjective L + have hL₂' : Surjective (Prod.snd ∘ L'.subtype) := by + simp only [← coe_snd (R := R), ← coe_comp, ← range_eq_top, LinearMap.range_comp, range_subtype] + simpa only [L', ← LinearMap.range_comp, snd_prod, range_eq_top] using + (LinearMap.snd ..).submoduleMap_surjective L + obtain ⟨e, he⟩ := goursat_surjective hL₁' hL₂' + use M', N', L'.goursatFst, L'.goursatSnd, e + rw [← he] + simp only [LinearMap.range_comp, Submodule.range_subtype, L'] + rw [comap_map_eq_self] + · ext ⟨m, n⟩ + constructor + · intro hmn + simp only [mem_map, LinearMap.mem_range, prod_apply, Subtype.exists, Prod.exists, coe_prodMap, + coe_subtype, Prod.map_apply, Prod.mk.injEq, exists_and_right, exists_eq_right_right, + exists_eq_right, M', N', fst_apply, snd_apply] + exact ⟨⟨n, hmn⟩, ⟨m, hmn⟩, ⟨m, n, hmn, rfl⟩⟩ + · simp only [mem_map, LinearMap.mem_range, prod_apply, Subtype.exists, Prod.exists, + coe_prodMap, coe_subtype, Prod.map_apply, Prod.mk.injEq, exists_and_right, + exists_eq_right_right, exists_eq_right, forall_exists_index, Pi.prod] + rintro hm hn m₁ n₁ hm₁n₁ ⟨hP, hQ⟩ + simp only [Subtype.ext_iff] at hP hQ + rwa [← hP, ← hQ] + · convert goursatFst_prod_goursatSnd_le (range <| P.prod Q) + ext ⟨m, n⟩ + simp_rw [mem_ker, coe_prodMap, Prod.map_apply, Submodule.mem_prod, Prod.zero_eq_mk, + Prod.ext_iff, ← mem_ker, ker_mkQ] + +end Submodule diff --git a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean index 2979de0ca709c..fd7f09efc5db7 100644 --- a/Mathlib/LinearAlgebra/InvariantBasisNumber.lean +++ b/Mathlib/LinearAlgebra/InvariantBasisNumber.lean @@ -24,10 +24,10 @@ Let `R` be a (not necessary commutative) ring. It is also useful to consider the following stronger conditions: -- the *rank condition*, witnessed by the type class `RankCondition R`, states that - the existence of a surjective linear map `(Fin n → R) →ₗ[R] (Fin m → R)` implies `m ≤ n` +- The *rank condition*, witnessed by the type class `RankCondition R`, states that + the existence of a surjective linear map `(Fin n → R) →ₗ[R] (Fin m → R)` implies `m ≤ n`. -- the *strong rank condition*, witnessed by the type class `StrongRankCondition R`, states +- The *strong rank condition*, witnessed by the type class `StrongRankCondition R`, states that the existence of an injective linear map `(Fin n → R) →ₗ[R] (Fin m → R)` implies `n ≤ m`. diff --git a/Mathlib/LinearAlgebra/LinearIndependent.lean b/Mathlib/LinearAlgebra/LinearIndependent.lean index eedfde103f8a0..88c16433bb3f7 100644 --- a/Mathlib/LinearAlgebra/LinearIndependent.lean +++ b/Mathlib/LinearAlgebra/LinearIndependent.lean @@ -7,7 +7,6 @@ import Mathlib.Algebra.BigOperators.Fin import Mathlib.Data.Set.Subsingleton import Mathlib.Lean.Expr.ExtraRecognizers import Mathlib.LinearAlgebra.Prod -import Mathlib.SetTheory.Cardinal.Basic import Mathlib.Tactic.FinCases import Mathlib.Tactic.LinearCombination import Mathlib.Tactic.Module @@ -82,13 +81,12 @@ linearly dependent, linear dependence, linearly independent, linear independence -/ +assert_not_exists Cardinal noncomputable section open Function Set Submodule -open Cardinal - universe u' u variable {ι : Type u'} {ι' : Type*} {R : Type*} {K : Type*} @@ -402,18 +400,6 @@ theorem linearIndependent_finset_map_embedding_subtype (s : Set M) obtain ⟨b, _hb, rfl⟩ := hy simp only [f, imp_self, Subtype.mk_eq_mk] -/-- If every finite set of linearly independent vectors has cardinality at most `n`, -then the same is true for arbitrary sets of linearly independent vectors. --/ -theorem linearIndependent_bounded_of_finset_linearIndependent_bounded {n : ℕ} - (H : ∀ s : Finset M, (LinearIndependent R fun i : s => (i : M)) → s.card ≤ n) : - ∀ s : Set M, LinearIndependent R ((↑) : s → M) → #s ≤ n := by - intro s li - apply Cardinal.card_le_of - intro t - rw [← Finset.card_map (Embedding.subtype s)] - apply H - apply linearIndependent_finset_map_embedding_subtype _ li section Subtype diff --git a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean index 9037e4a5083b9..44818b76d54be 100644 --- a/Mathlib/LinearAlgebra/Matrix/Adjugate.lean +++ b/Mathlib/LinearAlgebra/Matrix/Adjugate.lean @@ -70,11 +70,11 @@ variable (A : Matrix n n α) (b : n → α) Otherwise, the outcome of `cramerMap` is well-defined but not necessarily useful. -/ def cramerMap (i : n) : α := - (A.updateColumn i b).det + (A.updateCol i b).det theorem cramerMap_is_linear (i : n) : IsLinearMap α fun b => cramerMap A b i := - { map_add := det_updateColumn_add _ _ - map_smul := det_updateColumn_smul _ _ } + { map_add := det_updateCol_add _ _ + map_smul := det_updateCol_smul _ _ } theorem cramer_is_linear : IsLinearMap α (cramerMap A) := by constructor <;> intros <;> ext i @@ -90,11 +90,11 @@ theorem cramer_is_linear : IsLinearMap α (cramerMap A) := by def cramer (A : Matrix n n α) : (n → α) →ₗ[α] (n → α) := IsLinearMap.mk' (cramerMap A) (cramer_is_linear A) -theorem cramer_apply (i : n) : cramer A b i = (A.updateColumn i b).det := +theorem cramer_apply (i : n) : cramer A b i = (A.updateCol i b).det := rfl theorem cramer_transpose_apply (i : n) : cramer Aᵀ b i = (A.updateRow i b).det := by - rw [cramer_apply, updateColumn_transpose, det_transpose] + rw [cramer_apply, updateCol_transpose, det_transpose] theorem cramer_transpose_row_self (i : n) : Aᵀ.cramer (A i) = Pi.single i A.det := by ext j @@ -102,9 +102,9 @@ theorem cramer_transpose_row_self (i : n) : Aᵀ.cramer (A i) = Pi.single i A.de split_ifs with h · -- i = j: this entry should be `A.det` subst h - simp only [updateColumn_transpose, det_transpose, updateRow_eq_self] + simp only [updateCol_transpose, det_transpose, updateRow_eq_self] · -- i ≠ j: this entry should be 0 - rw [updateColumn_transpose, det_transpose] + rw [updateCol_transpose, det_transpose] apply det_zero_of_row_eq h rw [updateRow_self, updateRow_ne (Ne.symm h)] @@ -123,18 +123,18 @@ theorem cramer_one : cramer (1 : Matrix n n α) = 1 := by theorem cramer_smul (r : α) (A : Matrix n n α) : cramer (r • A) = r ^ (Fintype.card n - 1) • cramer A := - LinearMap.ext fun _ => funext fun _ => det_updateColumn_smul_left _ _ _ _ + LinearMap.ext fun _ => funext fun _ => det_updateCol_smul_left _ _ _ _ @[simp] theorem cramer_subsingleton_apply [Subsingleton n] (A : Matrix n n α) (b : n → α) (i : n) : - cramer A b i = b i := by rw [cramer_apply, det_eq_elem_of_subsingleton _ i, updateColumn_self] + cramer A b i = b i := by rw [cramer_apply, det_eq_elem_of_subsingleton _ i, updateCol_self] theorem cramer_zero [Nontrivial n] : cramer (0 : Matrix n n α) = 0 := by ext i j obtain ⟨j', hj'⟩ : ∃ j', j' ≠ j := exists_ne j apply det_eq_zero_of_column_eq_zero j' intro j'' - simp [updateColumn_ne hj'] + simp [updateCol_ne hj'] /-- Use linearity of `cramer` to take it out of a summation. -/ theorem sum_cramer {β} (s : Finset β) (f : β → n → α) : @@ -149,7 +149,7 @@ theorem sum_cramer_apply {β} (s : Finset β) (f : n → β → α) (i : n) : (Finset.sum_apply i s _).symm _ = cramer A (fun j : n => ∑ x ∈ s, f j x) i := by rw [sum_cramer, cramer_apply, cramer_apply] - simp only [updateColumn] + simp only [updateCol] congr with j congr apply Finset.sum_apply @@ -157,7 +157,7 @@ theorem sum_cramer_apply {β} (s : Finset β) (f : n → β → α) (i : n) : theorem cramer_submatrix_equiv (A : Matrix m m α) (e : n ≃ m) (b : n → α) : cramer (A.submatrix e e) b = cramer A (b ∘ e.symm) ∘ e := by ext i - simp_rw [Function.comp_apply, cramer_apply, updateColumn_submatrix_equiv, + simp_rw [Function.comp_apply, cramer_apply, updateCol_submatrix_equiv, det_submatrix_equiv_self e, Function.comp_def] theorem cramer_reindex (e : m ≃ n) (A : Matrix m m α) (b : n → α) : @@ -192,7 +192,7 @@ theorem adjugate_def (A : Matrix n n α) : adjugate A = of fun i => cramer Aᵀ theorem adjugate_apply (A : Matrix n n α) (i j : n) : adjugate A i j = (A.updateRow j (Pi.single i 1)).det := by - rw [adjugate_def, of_apply, cramer_apply, updateColumn_transpose, det_transpose] + rw [adjugate_def, of_apply, cramer_apply, updateCol_transpose, det_transpose] theorem adjugate_transpose (A : Matrix n n α) : (adjugate A)ᵀ = adjugate Aᵀ := by ext i j @@ -207,15 +207,15 @@ theorem adjugate_transpose (A : Matrix n n α) : (adjugate A)ᵀ = adjugate Aᵀ ext j' subst h have : σ j' = σ j ↔ j' = j := σ.injective.eq_iff - rw [updateRow_apply, updateColumn_apply] + rw [updateRow_apply, updateCol_apply] simp_rw [this] rw [← dite_eq_ite, ← dite_eq_ite] congr 1 with rfl rw [Pi.single_eq_same, Pi.single_eq_same] · -- Otherwise, we need to show that there is a `0` somewhere in the product. - have : (∏ j' : n, updateColumn A j (Pi.single i 1) (σ j') j') = 0 := by + have : (∏ j' : n, updateCol A j (Pi.single i 1) (σ j') j') = 0 := by apply prod_eq_zero (mem_univ j) - rw [updateColumn_self, Pi.single_eq_of_ne' h] + rw [updateCol_self, Pi.single_eq_of_ne' h] rw [this] apply prod_eq_zero (mem_univ (σ⁻¹ i)) erw [apply_symm_apply σ i, updateRow_self] @@ -297,7 +297,7 @@ theorem adjugate_zero [Nontrivial n] : adjugate (0 : Matrix n n α) = 0 := by obtain ⟨j', hj'⟩ : ∃ j', j' ≠ j := exists_ne j apply det_eq_zero_of_column_eq_zero j' intro j'' - simp [updateColumn_ne hj'] + simp [updateCol_ne hj'] @[simp] theorem adjugate_one : adjugate (1 : Matrix n n α) = 1 := by @@ -310,13 +310,13 @@ theorem adjugate_diagonal (v : n → α) : ext i j simp only [adjugate_def, cramer_apply, diagonal_transpose, of_apply] obtain rfl | hij := eq_or_ne i j - · rw [diagonal_apply_eq, diagonal_updateColumn_single, det_diagonal, + · rw [diagonal_apply_eq, diagonal_updateCol_single, det_diagonal, prod_update_of_mem (Finset.mem_univ _), sdiff_singleton_eq_erase, one_mul] · rw [diagonal_apply_ne _ hij] refine det_eq_zero_of_row_eq_zero j fun k => ?_ obtain rfl | hjk := eq_or_ne k j - · rw [updateColumn_self, Pi.single_eq_of_ne' hij] - · rw [updateColumn_ne hjk, diagonal_apply_ne' _ hjk] + · rw [updateCol_self, Pi.single_eq_of_ne' hij] + · rw [updateCol_ne hjk, diagonal_apply_ne' _ hjk] theorem _root_.RingHom.map_adjugate {R S : Type*} [CommRing R] [CommRing S] (f : R →+* S) (M : Matrix n n R) : f.mapMatrix M.adjugate = Matrix.adjugate (f.mapMatrix M) := by diff --git a/Mathlib/LinearAlgebra/Matrix/Basis.lean b/Mathlib/LinearAlgebra/Matrix/Basis.lean index f06b9e9d99955..f7bd16c3469f5 100644 --- a/Mathlib/LinearAlgebra/Matrix/Basis.lean +++ b/Mathlib/LinearAlgebra/Matrix/Basis.lean @@ -76,9 +76,9 @@ theorem toMatrix_self [DecidableEq ι] : e.toMatrix e = 1 := by simp [Basis.equivFun, Matrix.one_apply, Finsupp.single_apply, eq_comm] theorem toMatrix_update [DecidableEq ι'] (x : M) : - e.toMatrix (Function.update v j x) = Matrix.updateColumn (e.toMatrix v) j (e.repr x) := by + e.toMatrix (Function.update v j x) = Matrix.updateCol (e.toMatrix v) j (e.repr x) := by ext i' k - rw [Basis.toMatrix, Matrix.updateColumn_apply, e.toMatrix_apply] + rw [Basis.toMatrix, Matrix.updateCol_apply, e.toMatrix_apply] split_ifs with h · rw [h, update_same j x v] · rw [update_noteq h] diff --git a/Mathlib/LinearAlgebra/Matrix/Block.lean b/Mathlib/LinearAlgebra/Matrix/Block.lean index 401caa2ef1eff..26de8f3e90de3 100644 --- a/Mathlib/LinearAlgebra/Matrix/Block.lean +++ b/Mathlib/LinearAlgebra/Matrix/Block.lean @@ -344,7 +344,7 @@ theorem blockTriangular_inv_of_blockTriangular [LinearOrder α] [Invertible M] have hb' : image b' univ ⊂ image b univ := by convert image_subtype_univ_ssubset_image_univ k b _ (fun a => a < k) (lt_irrefl _) convert max'_mem (α := α) _ _ - have hij' : b' ⟨j, hij.trans hi⟩ < b' ⟨i, hi⟩ := by simp_rw [hij] - simp [hM.inv_toBlock k, (ih (image b' univ) hb' hA rfl hij').symm] + have hij' : b' ⟨j, hij.trans hi⟩ < b' ⟨i, hi⟩ := by simp_rw [b', hij] + simp [A, hM.inv_toBlock k, (ih (image b' univ) hb' hA rfl hij').symm] end Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean index f136828ae7921..e5d7288e96387 100644 --- a/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean +++ b/Mathlib/LinearAlgebra/Matrix/Charpoly/Coeff.lean @@ -317,9 +317,9 @@ lemma reverse_charpoly (M : Matrix n n R) : let q : R[T;T⁻¹] := det (1 - scalar n t * M.map LaurentPolynomial.C) have ht : t_inv * t = 1 := by rw [← T_add, neg_add_cancel, T_zero] have hp : toLaurentAlg M.charpoly = p := by - simp [p, charpoly, charmatrix, AlgHom.map_det, map_sub, map_smul'] + simp [p, t, charpoly, charmatrix, AlgHom.map_det, map_sub, map_smul'] have hq : toLaurentAlg M.charpolyRev = q := by - simp [q, charpolyRev, AlgHom.map_det, map_sub, map_smul', smul_eq_diagonal_mul] + simp [q, t, charpolyRev, AlgHom.map_det, map_sub, map_smul', smul_eq_diagonal_mul] suffices t_inv ^ Fintype.card n * p = invert q by apply toLaurent_injective rwa [toLaurent_reverse, ← coe_toLaurentAlg, hp, hq, ← involutive_invert.injective.eq_iff, @@ -327,7 +327,7 @@ lemma reverse_charpoly (M : Matrix n n R) : ← mul_one (Fintype.card n : ℤ), ← T_pow, map_pow, invert_T, mul_comm] rw [← det_smul, smul_sub, scalar_apply, ← diagonal_smul, Pi.smul_def, smul_eq_mul, ht, diagonal_one, invert.map_det] - simp [map_sub, _root_.map_one, _root_.map_mul, t, map_smul', smul_eq_diagonal_mul] + simp [t_inv, map_sub, _root_.map_one, _root_.map_mul, t, map_smul', smul_eq_diagonal_mul] @[simp] lemma eval_charpolyRev : diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean index bd291498d65eb..274f69211c711 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/Basic.lean @@ -10,6 +10,7 @@ import Mathlib.Data.Matrix.RowCol import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.GroupTheory.Perm.Fin import Mathlib.LinearAlgebra.Alternating.Basic +import Mathlib.LinearAlgebra.Matrix.SemiringInverse /-! # Determinant of a matrix @@ -62,6 +63,12 @@ theorem det_apply (M : Matrix n n R) : M.det = ∑ σ : Perm n, Equiv.Perm.sign theorem det_apply' (M : Matrix n n R) : M.det = ∑ σ : Perm n, ε σ * ∏ i, M (σ i) i := by simp [det_apply, Units.smul_def] +theorem det_eq_detp_sub_detp (M : Matrix n n R) : M.det = M.detp 1 - M.detp (-1) := by + rw [det_apply, ← Equiv.sum_comp (Equiv.inv (Perm n)), ← ofSign_disjUnion, sum_disjUnion] + simp_rw [inv_apply, sign_inv, sub_eq_add_neg, detp, ← sum_neg_distrib] + refine congr_arg₂ (· + ·) (sum_congr rfl fun σ hσ ↦ ?_) (sum_congr rfl fun σ hσ ↦ ?_) <;> + rw [mem_ofSign.mp hσ, ← Equiv.prod_comp σ] <;> simp + @[simp] theorem det_diagonal {d : n → R} : det (diagonal d) = ∏ i, d i := by rw [det_apply'] @@ -342,8 +349,10 @@ theorem det_updateRow_eq_zero (h : i ≠ j) : (M.updateRow j (M i)).det = 0 := det_zero_of_row_eq h (by simp [h]) /-- If we repeat a column of a matrix, we get a matrix of determinant zero. -/ -theorem det_updateColumn_eq_zero (h : i ≠ j) : - (M.updateColumn j (fun k ↦ M k i)).det = 0 := det_zero_of_column_eq h (by simp [h]) +theorem det_updateCol_eq_zero (h : i ≠ j) : + (M.updateCol j (fun k ↦ M k i)).det = 0 := det_zero_of_column_eq h (by simp [h]) + +@[deprecated (since := "2024-12-11")] alias det_updateColumn_eq_zero := det_updateCol_eq_zero end DetZero @@ -351,32 +360,37 @@ theorem det_updateRow_add (M : Matrix n n R) (j : n) (u v : n → R) : det (updateRow M j <| u + v) = det (updateRow M j u) + det (updateRow M j v) := (detRowAlternating : (n → R) [⋀^n]→ₗ[R] R).map_update_add M j u v -theorem det_updateColumn_add (M : Matrix n n R) (j : n) (u v : n → R) : - det (updateColumn M j <| u + v) = det (updateColumn M j u) + det (updateColumn M j v) := by +theorem det_updateCol_add (M : Matrix n n R) (j : n) (u v : n → R) : + det (updateCol M j <| u + v) = det (updateCol M j u) + det (updateCol M j v) := by rw [← det_transpose, ← updateRow_transpose, det_updateRow_add] simp [updateRow_transpose, det_transpose] +@[deprecated (since := "2024-12-11")] alias det_updateColumn_add := det_updateCol_add + theorem det_updateRow_smul (M : Matrix n n R) (j : n) (s : R) (u : n → R) : det (updateRow M j <| s • u) = s * det (updateRow M j u) := (detRowAlternating : (n → R) [⋀^n]→ₗ[R] R).map_update_smul M j s u -theorem det_updateColumn_smul (M : Matrix n n R) (j : n) (s : R) (u : n → R) : - det (updateColumn M j <| s • u) = s * det (updateColumn M j u) := by +theorem det_updateCol_smul (M : Matrix n n R) (j : n) (s : R) (u : n → R) : + det (updateCol M j <| s • u) = s * det (updateCol M j u) := by rw [← det_transpose, ← updateRow_transpose, det_updateRow_smul] simp [updateRow_transpose, det_transpose] +@[deprecated (since := "2024-12-11")] alias det_updateColumn_smul := det_updateCol_smul + theorem det_updateRow_smul_left (M : Matrix n n R) (j : n) (s : R) (u : n → R) : det (updateRow (s • M) j u) = s ^ (Fintype.card n - 1) * det (updateRow M j u) := MultilinearMap.map_update_smul_left _ M j s u @[deprecated (since := "2024-11-03")] alias det_updateRow_smul' := det_updateRow_smul_left -theorem det_updateColumn_smul_left (M : Matrix n n R) (j : n) (s : R) (u : n → R) : - det (updateColumn (s • M) j u) = s ^ (Fintype.card n - 1) * det (updateColumn M j u) := by +theorem det_updateCol_smul_left (M : Matrix n n R) (j : n) (s : R) (u : n → R) : + det (updateCol (s • M) j u) = s ^ (Fintype.card n - 1) * det (updateCol M j u) := by rw [← det_transpose, ← updateRow_transpose, transpose_smul, det_updateRow_smul_left] simp [updateRow_transpose, det_transpose] -@[deprecated (since := "2024-11-03")] alias det_updateColumn_smul' := det_updateColumn_smul_left +@[deprecated (since := "2024-12-11")] alias det_updateColumn_smul' := det_updateCol_smul_left +@[deprecated (since := "2024-12-11")] alias det_updateColumn_smul_left := det_updateCol_smul_left theorem det_updateRow_sum_aux (M : Matrix n n R) {j : n} (s : Finset n) (hj : j ∉ s) (c : n → R) (a : R) : @@ -398,12 +412,14 @@ theorem det_updateRow_sum (A : Matrix n n R) (j : n) (c : n → R) : /-- If we replace a column of a matrix by a linear combination of its columns, then the determinant is multiplied by the coefficient of that column. -/ -theorem det_updateColumn_sum (A : Matrix n n R) (j : n) (c : n → R) : - (A.updateColumn j (fun k ↦ ∑ i, (c i) • A k i)).det = (c j) • A.det := by +theorem det_updateCol_sum (A : Matrix n n R) (j : n) (c : n → R) : + (A.updateCol j (fun k ↦ ∑ i, (c i) • A k i)).det = (c j) • A.det := by rw [← det_transpose, ← updateRow_transpose, ← det_transpose A] convert det_updateRow_sum A.transpose j c simp only [smul_eq_mul, Finset.sum_apply, Pi.smul_apply, transpose_apply] +@[deprecated (since := "2024-12-11")] alias det_updateColumn_sum := det_updateCol_sum + section DetEq /-! ### `det_eq` section @@ -431,21 +447,26 @@ theorem det_updateRow_add_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) : simp [det_updateRow_add, det_zero_of_row_eq hij (updateRow_self.trans (updateRow_ne hij.symm).symm)] -theorem det_updateColumn_add_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) : - det (updateColumn A i fun k => A k i + A k j) = det A := by +theorem det_updateCol_add_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) : + det (updateCol A i fun k => A k i + A k j) = det A := by rw [← det_transpose, ← updateRow_transpose, ← det_transpose A] exact det_updateRow_add_self Aᵀ hij +@[deprecated (since := "2024-12-11")] alias det_updateColumn_add_self := det_updateCol_add_self + theorem det_updateRow_add_smul_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) (c : R) : det (updateRow A i (A i + c • A j)) = det A := by simp [det_updateRow_add, det_updateRow_smul, det_zero_of_row_eq hij (updateRow_self.trans (updateRow_ne hij.symm).symm)] -theorem det_updateColumn_add_smul_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) (c : R) : - det (updateColumn A i fun k => A k i + c • A k j) = det A := by +theorem det_updateCol_add_smul_self (A : Matrix n n R) {i j : n} (hij : i ≠ j) (c : R) : + det (updateCol A i fun k => A k i + c • A k j) = det A := by rw [← det_transpose, ← updateRow_transpose, ← det_transpose A] exact det_updateRow_add_smul_self Aᵀ hij c +@[deprecated (since := "2024-12-11")] +alias det_updateColumn_add_smul_self := det_updateCol_add_smul_self + theorem det_eq_of_forall_row_eq_smul_add_const_aux {A B : Matrix n n R} {s : Finset n} : ∀ (c : n → R) (_ : ∀ i, i ∉ s → c i = 0) (k : n) (_ : k ∉ s) (_ : ∀ i j, A i j = B i j + c i * B k j), det A = det B := by diff --git a/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean b/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean index 8300120633c79..712f006504c42 100644 --- a/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean +++ b/Mathlib/LinearAlgebra/Matrix/Determinant/TotallyUnimodular.lean @@ -158,20 +158,26 @@ lemma one_fromRows_isTotallyUnimodular_iff [DecidableEq n] (A : Matrix m n R) : aesop rw [hA, reindex_isTotallyUnimodular, fromRows_one_isTotallyUnimodular_iff] -lemma fromColumns_one_isTotallyUnimodular_iff [DecidableEq m] (A : Matrix m n R) : - (fromColumns A (1 : Matrix m m R)).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by - rw [←transpose_isTotallyUnimodular_iff, transpose_fromColumns, transpose_one, +lemma fromCols_one_isTotallyUnimodular_iff [DecidableEq m] (A : Matrix m n R) : + (fromCols A (1 : Matrix m m R)).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by + rw [←transpose_isTotallyUnimodular_iff, transpose_fromCols, transpose_one, fromRows_one_isTotallyUnimodular_iff, transpose_isTotallyUnimodular_iff] -lemma one_fromColumns_isTotallyUnimodular_iff [DecidableEq m] (A : Matrix m n R) : - (fromColumns (1 : Matrix m m R) A).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by - rw [←transpose_isTotallyUnimodular_iff, transpose_fromColumns, transpose_one, +@[deprecated (since := "2024-12-11")] +alias fromColumns_one_isTotallyUnimodular_iff := fromCols_one_isTotallyUnimodular_iff + +lemma one_fromCols_isTotallyUnimodular_iff [DecidableEq m] (A : Matrix m n R) : + (fromCols (1 : Matrix m m R) A).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by + rw [←transpose_isTotallyUnimodular_iff, transpose_fromCols, transpose_one, one_fromRows_isTotallyUnimodular_iff, transpose_isTotallyUnimodular_iff] +@[deprecated (since := "2024-12-11")] +alias one_fromColumns_isTotallyUnimodular_iff := one_fromCols_isTotallyUnimodular_iff + alias ⟨_, IsTotallyUnimodular.fromRows_one⟩ := fromRows_one_isTotallyUnimodular_iff alias ⟨_, IsTotallyUnimodular.one_fromRows⟩ := one_fromRows_isTotallyUnimodular_iff -alias ⟨_, IsTotallyUnimodular.fromColumns_one⟩ := fromColumns_one_isTotallyUnimodular_iff -alias ⟨_, IsTotallyUnimodular.one_fromColumns⟩ := one_fromColumns_isTotallyUnimodular_iff +alias ⟨_, IsTotallyUnimodular.fromCols_one⟩ := fromCols_one_isTotallyUnimodular_iff +alias ⟨_, IsTotallyUnimodular.one_fromCols⟩ := one_fromCols_isTotallyUnimodular_iff lemma fromRows_row0_isTotallyUnimodular_iff (A : Matrix m n R) : (fromRows A (row m' 0)).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by @@ -182,9 +188,12 @@ lemma fromRows_row0_isTotallyUnimodular_iff (A : Matrix m n R) : ext x simp [Pi.single_apply] -lemma fromColumns_col0_isTotallyUnimodular_iff (A : Matrix m n R) : - (fromColumns A (col n' 0)).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by - rw [← transpose_isTotallyUnimodular_iff, transpose_fromColumns, transpose_col, +lemma fromCols_col0_isTotallyUnimodular_iff (A : Matrix m n R) : + (fromCols A (col n' 0)).IsTotallyUnimodular ↔ A.IsTotallyUnimodular := by + rw [← transpose_isTotallyUnimodular_iff, transpose_fromCols, transpose_col, fromRows_row0_isTotallyUnimodular_iff, transpose_isTotallyUnimodular_iff] +@[deprecated (since := "2024-12-11")] +alias fromColumns_col0_isTotallyUnimodular_iff := fromCols_col0_isTotallyUnimodular_iff + end Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean index ff4b403c74f6f..882fe25b80d27 100644 --- a/Mathlib/LinearAlgebra/Matrix/Diagonal.lean +++ b/Mathlib/LinearAlgebra/Matrix/Diagonal.lean @@ -4,6 +4,7 @@ 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.Dimension.LinearMap +import Mathlib.LinearAlgebra.Matrix.ToLin /-! # Diagonal matrices diff --git a/Mathlib/LinearAlgebra/Matrix/Ideal.lean b/Mathlib/LinearAlgebra/Matrix/Ideal.lean index b4de0f855d6dc..ef88aeec52f02 100644 --- a/Mathlib/LinearAlgebra/Matrix/Ideal.lean +++ b/Mathlib/LinearAlgebra/Matrix/Ideal.lean @@ -6,7 +6,7 @@ Authors: Jujian Zhang, Wojciech Nawrocki import Mathlib.Data.Matrix.Basis import Mathlib.RingTheory.Ideal.Lattice import Mathlib.RingTheory.TwoSidedIdeal.Operations -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Ideal /-! # Ideals in a matrix ring diff --git a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean index 51f9cb372d6b2..b279eda8cbc9c 100644 --- a/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean +++ b/Mathlib/LinearAlgebra/Matrix/NonsingularInverse.lean @@ -6,7 +6,9 @@ Authors: Anne Baanen, Lu-Ming Zhang import Mathlib.Data.Matrix.Invertible import Mathlib.LinearAlgebra.FiniteDimensional.Defs import Mathlib.LinearAlgebra.Matrix.Adjugate +import Mathlib.LinearAlgebra.Matrix.SemiringInverse import Mathlib.LinearAlgebra.Matrix.Trace +import Mathlib.LinearAlgebra.Matrix.ToLin /-! # Nonsingular inverses @@ -107,29 +109,6 @@ def invertibleEquivDetInvertible : Invertible A ≃ Invertible A.det where left_inv _ := Subsingleton.elim _ _ right_inv _ := Subsingleton.elim _ _ -variable {A B} - -theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 := - suffices ∀ A B : Matrix n n α, A * B = 1 → B * A = 1 from ⟨this A B, this B A⟩ - fun A B h => by - letI : Invertible B.det := detInvertibleOfLeftInverse _ _ h - letI : Invertible B := invertibleOfDetInvertible B - calc - B * A = B * A * (B * ⅟ B) := by rw [mul_invOf_self, Matrix.mul_one] - _ = B * (A * B * ⅟ B) := by simp only [Matrix.mul_assoc] - _ = B * ⅟ B := by rw [h, Matrix.one_mul] - _ = 1 := mul_invOf_self B - -variable (A B) - -/-- We can construct an instance of invertible A if A has a left inverse. -/ -def invertibleOfLeftInverse (h : B * A = 1) : Invertible A := - ⟨B, h, mul_eq_one_comm.mp h⟩ - -/-- We can construct an instance of invertible A if A has a right inverse. -/ -def invertibleOfRightInverse (h : A * B = 1) : Invertible A := - ⟨B, mul_eq_one_comm.mp h, h⟩ - /-- Given a proof that `A.det` has a constructive inverse, lift `A` to `(Matrix n n α)ˣ`-/ def unitOfDetInvertible [Invertible A.det] : (Matrix n n α)ˣ := @unitOfInvertible _ _ A (invertibleOfDetInvertible A) @@ -150,18 +129,6 @@ theorem isUnit_det_of_invertible [Invertible A] : IsUnit A.det := variable {A B} -theorem isUnit_of_left_inverse (h : B * A = 1) : IsUnit A := - ⟨⟨A, B, mul_eq_one_comm.mp h, h⟩, rfl⟩ - -theorem exists_left_inverse_iff_isUnit : (∃ B, B * A = 1) ↔ IsUnit A := - ⟨fun ⟨_, h⟩ ↦ isUnit_of_left_inverse h, fun h ↦ have := h.invertible; ⟨⅟A, invOf_mul_self' A⟩⟩ - -theorem isUnit_of_right_inverse (h : A * B = 1) : IsUnit A := - ⟨⟨A, B, h, mul_eq_one_comm.mp h⟩, rfl⟩ - -theorem exists_right_inverse_iff_isUnit : (∃ B, A * B = 1) ↔ IsUnit A := - ⟨fun ⟨_, h⟩ ↦ isUnit_of_right_inverse h, fun h ↦ have := h.invertible; ⟨⅟A, mul_invOf_self' A⟩⟩ - theorem isUnit_det_of_left_inverse (h : B * A = 1) : IsUnit A.det := @isUnit_of_invertible _ _ _ (detInvertibleOfLeftInverse _ _ h) @@ -176,20 +143,6 @@ theorem det_ne_zero_of_right_inverse [Nontrivial α] (h : A * B = 1) : A.det ≠ end Invertible - -section - -variable [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] [CommRing α] - -/-- A version of `mul_eq_one_comm` that works for square matrices with rectangular types. -/ -theorem mul_eq_one_comm_of_equiv {A : Matrix m n α} {B : Matrix n m α} (e : m ≃ n) : - A * B = 1 ↔ B * A = 1 := by - refine (reindex e e).injective.eq_iff.symm.trans ?_ - rw [reindex_apply, reindex_apply, submatrix_one_equiv, ← submatrix_mul_equiv _ _ _ (.refl _), - mul_eq_one_comm, submatrix_mul_equiv, coe_refl, submatrix_id_id] - -end - section Inv variable [Fintype n] [DecidableEq n] [CommRing α] diff --git a/Mathlib/LinearAlgebra/Matrix/Permanent.lean b/Mathlib/LinearAlgebra/Matrix/Permanent.lean index fa1620053c90a..38b6d0b855c68 100644 --- a/Mathlib/LinearAlgebra/Matrix/Permanent.lean +++ b/Mathlib/LinearAlgebra/Matrix/Permanent.lean @@ -3,9 +3,8 @@ Copyright (c) 2024 Moritz Firsching. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Moritz Firsching -/ -import Mathlib.Algebra.BigOperators.GroupWithZero.Finset import Mathlib.Data.Fintype.Perm -import Mathlib.Data.Matrix.Diagonal +import Mathlib.Data.Matrix.RowCol /-! # Permanent of a matrix @@ -83,4 +82,32 @@ theorem permanent_permute_rows (σ : Perm n) (M : Matrix n n R) : (M.submatrix id σ).permanent = M.permanent := by rw [← permanent_transpose, transpose_submatrix, permanent_permute_cols, permanent_transpose] +@[simp] +theorem permanent_smul (M : Matrix n n R) (c : R) : + permanent (c • M) = c ^ Fintype.card n * permanent M := by + simp only [permanent, smul_apply, smul_eq_mul, Finset.mul_sum] + congr + ext + rw [mul_comm] + conv in ∏ _ , c * _ => simp [mul_comm c]; + exact prod_mul_pow_card.symm + +@[simp] +theorem permanent_updateCol_smul (M : Matrix n n R) (j : n) (c : R) (u : n → R) : + permanent (updateCol M j <| c • u) = c * permanent (updateCol M j u) := by + simp only [permanent, ← mul_prod_erase _ _ (mem_univ j), updateCol_self, Pi.smul_apply, + smul_eq_mul, mul_sum, ← mul_assoc] + congr 1 with p + rw [Finset.prod_congr rfl (fun i hi ↦ ?_)] + simp only [ne_eq, ne_of_mem_erase hi, not_false_eq_true, updateCol_ne] + +@[deprecated (since := "2024-12-11")] +alias permanent_updateColumn_smul := permanent_updateCol_smul + +@[simp] +theorem permanent_updateRow_smul (M : Matrix n n R) (j : n) (c : R) (u : n → R) : + permanent (updateRow M j <| c • u) = c * permanent (updateRow M j u) := by + rw [← permanent_transpose, ← updateCol_transpose, permanent_updateCol_smul, + updateCol_transpose, permanent_transpose] + end Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/SemiringInverse.lean b/Mathlib/LinearAlgebra/Matrix/SemiringInverse.lean new file mode 100644 index 0000000000000..53f0096ec53d4 --- /dev/null +++ b/Mathlib/LinearAlgebra/Matrix/SemiringInverse.lean @@ -0,0 +1,252 @@ +/- +Copyright (c) 2024 Thomas Browning. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Thomas Browning +-/ +import Mathlib.Data.Fintype.Perm +import Mathlib.Data.Matrix.Mul +import Mathlib.GroupTheory.Perm.Sign + +/-! +# Nonsingular inverses over semirings + +This files proves `A * B = 1 ↔ B * A = 1` for square matrices over a commutative semiring. + +-/ + +open Equiv Equiv.Perm Finset + +variable {n m R : Type*} [Fintype m] [Fintype n] [DecidableEq m] [DecidableEq n] [CommSemiring R] + +variable (s : ℤˣ) (A B : Matrix n n R) (i j : n) + +namespace Matrix + +/-- The determinant, but only the terms of a given sign. -/ +def detp : R := ∑ σ ∈ ofSign s, ∏ k, A k (σ k) + +@[simp] +lemma detp_one_one : detp 1 (1 : Matrix n n R) = 1 := by + rw [detp, sum_eq_single_of_mem 1] + · simp [one_apply] + · simp [ofSign] + · rintro σ - hσ1 + obtain ⟨i, hi⟩ := not_forall.mp (mt Perm.ext_iff.mpr hσ1) + exact prod_eq_zero (mem_univ i) (one_apply_ne' hi) + +@[simp] +lemma detp_neg_one_one : detp (-1) (1 : Matrix n n R) = 0 := by + rw [detp, sum_eq_zero] + intro σ hσ + have hσ1 : σ ≠ 1 := by + contrapose! hσ + rw [hσ, mem_ofSign, sign_one] + decide + obtain ⟨i, hi⟩ := not_forall.mp (mt Perm.ext_iff.mpr hσ1) + exact prod_eq_zero (mem_univ i) (one_apply_ne' hi) + +/-- The adjugate matrix, but only the terms of a given sign. -/ +def adjp : Matrix n n R := + of fun i j ↦ ∑ σ ∈ (ofSign s).filter (· j = i), ∏ k ∈ {j}ᶜ, A k (σ k) + +lemma adjp_apply (i j : n) : + adjp s A i j = ∑ σ ∈ (ofSign s).filter (· j = i), ∏ k ∈ {j}ᶜ, A k (σ k) := + rfl + +theorem detp_mul : + detp 1 (A * B) + (detp 1 A * detp (-1) B + detp (-1) A * detp 1 B) = + detp (-1) (A * B) + (detp 1 A * detp 1 B + detp (-1) A * detp (-1) B) := by + have hf {s t} {σ : Perm n} (hσ : σ ∈ ofSign s) : + ofSign (t * s) = (ofSign t).map (mulRightEmbedding σ) := by + ext τ + simp_rw [mem_map, mulRightEmbedding_apply, ← eq_mul_inv_iff_mul_eq, exists_eq_right, + mem_ofSign, _root_.map_mul, _root_.map_inv, mul_inv_eq_iff_eq_mul, mem_ofSign.mp hσ] + have h {s t} : detp s A * detp t B = + ∑ σ ∈ ofSign s, ∑ τ ∈ ofSign (t * s), ∏ k, A k (σ k) * B (σ k) (τ k) := by + simp_rw [detp, sum_mul_sum, prod_mul_distrib] + refine sum_congr rfl fun σ hσ ↦ ?_ + simp_rw [hf hσ, sum_map, mulRightEmbedding_apply, Perm.mul_apply] + exact sum_congr rfl fun τ hτ ↦ (congr_arg (_ * ·) (Equiv.prod_comp σ _).symm) + let ι : Perm n ↪ (n → n) := ⟨_, coe_fn_injective⟩ + have hι {σ x} : ι σ x = σ x := rfl + let bij : Finset (n → n) := (disjUnion (ofSign 1) (ofSign (-1)) ofSign_disjoint).map ι + replace h (s) : detp s (A * B) = + ∑ σ ∈ bijᶜ, ∑ τ ∈ ofSign s, ∏ i : n, A i (σ i) * B (σ i) (τ i) + + (detp 1 A * detp s B + detp (-1) A * detp (-s) B) := by + simp_rw [h, neg_mul_neg, mul_one, detp, mul_apply, prod_univ_sum, Fintype.piFinset_univ] + rw [sum_comm, ← sum_compl_add_sum bij, sum_map, sum_disjUnion] + simp_rw [hι] + rw [h, h, neg_neg, add_assoc] + conv_rhs => rw [add_assoc] + refine congr_arg₂ (· + ·) (sum_congr rfl fun σ hσ ↦ ?_) (add_comm _ _) + replace hσ : ¬ Function.Injective σ := by + contrapose! hσ + rw [not_mem_compl, mem_map, ofSign_disjUnion] + exact ⟨Equiv.ofBijective σ hσ.bijective_of_finite, mem_univ _, rfl⟩ + obtain ⟨i, j, hσ, hij⟩ := Function.not_injective_iff.mp hσ + replace hσ k : σ (swap i j k) = σ k := by + rw [swap_apply_def] + split_ifs with h h <;> simp only [hσ, h] + rw [← mul_neg_one, hf (mem_ofSign.mpr (sign_swap hij)), sum_map] + simp_rw [prod_mul_distrib, mulRightEmbedding_apply, Perm.mul_apply] + refine sum_congr rfl fun τ hτ ↦ congr_arg (_ * ·) ?_ + rw [← Equiv.prod_comp (swap i j)] + simp only [hσ] + +theorem mul_adjp_apply_eq : (A * adjp s A) i i = detp s A := by + have key := sum_fiberwise_eq_sum_filter (ofSign s) univ (· i) fun σ ↦ ∏ k, A k (σ k) + simp_rw [mem_univ, filter_True] at key + simp_rw [mul_apply, adjp_apply, mul_sum, detp, ← key] + refine sum_congr rfl fun x hx ↦ sum_congr rfl fun σ hσ ↦ ?_ + rw [← prod_mul_prod_compl ({i} : Finset n), prod_singleton, (mem_filter.mp hσ).2] + +theorem mul_adjp_apply_ne (h : i ≠ j) : (A * adjp 1 A) i j = (A * adjp (-1) A) i j := by + simp_rw [mul_apply, adjp_apply, mul_sum, sum_sigma'] + let f : (Σ x : n, Perm n) → (Σ x : n, Perm n) := fun ⟨x, σ⟩ ↦ ⟨σ i, σ * swap i j⟩ + let t s : Finset (Σ x : n, Perm n) := univ.sigma fun x ↦ (ofSign s).filter fun σ ↦ σ j = x + have hf {s} : ∀ p ∈ t s, f (f p) = p := by + intro ⟨x, σ⟩ hp + rw [mem_sigma, mem_filter, mem_ofSign] at hp + simp_rw [f, Perm.mul_apply, swap_apply_left, hp.2.2, mul_swap_mul_self] + refine sum_bij' (fun p _ ↦ f p) (fun p _ ↦ f p) ?_ ?_ hf hf ?_ + · intro ⟨x, σ⟩ hp + rw [mem_sigma, mem_filter, mem_ofSign] at hp ⊢ + rw [Perm.mul_apply, sign_mul, hp.2.1, sign_swap h, swap_apply_right] + exact ⟨mem_univ (σ i), rfl, rfl⟩ + · intro ⟨x, σ⟩ hp + rw [mem_sigma, mem_filter, mem_ofSign] at hp ⊢ + rw [Perm.mul_apply, sign_mul, hp.2.1, sign_swap h, swap_apply_right] + exact ⟨mem_univ (σ i), rfl, rfl⟩ + · intro ⟨x, σ⟩ hp + rw [mem_sigma, mem_filter, mem_ofSign] at hp + have key : ({j}ᶜ : Finset n) = disjUnion ({i} : Finset n) ({i, j} : Finset n)ᶜ (by simp) := by + rw [singleton_disjUnion, cons_eq_insert, compl_insert, insert_erase] + rwa [mem_compl, mem_singleton] + simp_rw [key, prod_disjUnion, prod_singleton, Perm.mul_apply, swap_apply_left, ← mul_assoc] + rw [mul_comm (A i x) (A i (σ i)), hp.2.2] + refine congr_arg _ (prod_congr rfl fun x hx ↦ ?_) + rw [mem_compl, mem_insert, mem_singleton, not_or] at hx + rw [swap_apply_of_ne_of_ne hx.1 hx.2] + +theorem mul_adjp_add_detp : A * adjp 1 A + detp (-1) A • 1 = A * adjp (-1) A + detp 1 A • 1 := by + ext i j + rcases eq_or_ne i j with rfl | h <;> simp_rw [add_apply, smul_apply, smul_eq_mul] + · simp_rw [mul_adjp_apply_eq, one_apply_eq, mul_one, add_comm] + · simp_rw [mul_adjp_apply_ne A i j h, one_apply_ne h, mul_zero] + +variable {A B} + +theorem isAddUnit_mul (hAB : A * B = 1) (i j k : n) (hij : i ≠ j) : IsAddUnit (A i k * B k j) := by + revert k + rw [← IsAddUnit.sum_univ_iff, ← mul_apply, hAB, one_apply_ne hij] + exact isAddUnit_zero + +theorem isAddUnit_detp_mul_detp (hAB : A * B = 1) : + IsAddUnit (detp 1 A * detp (-1) B + detp (-1) A * detp 1 B) := by + suffices h : ∀ {s t}, s ≠ t → IsAddUnit (detp s A * detp t B) from + (h (by decide)).add (h (by decide)) + intro s t h + simp_rw [detp, sum_mul_sum, IsAddUnit.sum_iff] + intro σ hσ τ hτ + rw [mem_ofSign] at hσ hτ + rw [← hσ, ← hτ, ← sign_inv] at h + replace h := ne_of_apply_ne sign h + rw [ne_eq, eq_comm, eq_inv_iff_mul_eq_one, eq_comm] at h + simp_rw [Equiv.ext_iff, not_forall, Perm.mul_apply, Perm.one_apply] at h + obtain ⟨k, hk⟩ := h + rw [mul_comm, ← Equiv.prod_comp σ, mul_comm, ← prod_mul_distrib, + ← mul_prod_erase univ _ (mem_univ k), ← smul_eq_mul] + exact (isAddUnit_mul hAB k (τ (σ k)) (σ k) hk).smul_right _ + +theorem isAddUnit_detp_smul_mul_adjp (hAB : A * B = 1) : + IsAddUnit (detp 1 A • (B * adjp (-1) B) + detp (-1) A • (B * adjp 1 B)) := by + suffices h : ∀ {s t}, s ≠ t → IsAddUnit (detp s A • (B * adjp t B)) from + (h (by decide)).add (h (by decide)) + intro s t h + rw [isAddUnit_iff] + intro i j + simp_rw [smul_apply, smul_eq_mul, mul_apply, detp, adjp_apply, mul_sum, sum_mul, + IsAddUnit.sum_iff] + intro k hk σ hσ τ hτ + rw [mem_filter] at hσ + rw [mem_ofSign] at hσ hτ + rw [← hσ.1, ← hτ, ← sign_inv] at h + replace h := ne_of_apply_ne sign h + rw [ne_eq, eq_comm, eq_inv_iff_mul_eq_one] at h + obtain ⟨l, hl1, hl2⟩ := exists_ne_of_one_lt_card (one_lt_card_support_of_ne_one h) (τ⁻¹ j) + rw [mem_support, ne_comm] at hl1 + rw [ne_eq, ← mem_singleton, ← mem_compl] at hl2 + rw [← prod_mul_prod_compl {τ⁻¹ j}, mul_mul_mul_comm, mul_comm, ← smul_eq_mul] + apply IsAddUnit.smul_right + have h0 : ∀ k, k ∈ ({τ⁻¹ j} : Finset n)ᶜ ↔ τ k ∈ ({j} : Finset n)ᶜ := by + simp [show τ⁻¹ = τ.symm from rfl, eq_symm_apply] + rw [← prod_equiv τ h0 fun _ _ ↦ rfl, ← prod_mul_distrib, ← mul_prod_erase _ _ hl2, ← smul_eq_mul] + exact (isAddUnit_mul hAB l (σ (τ l)) (τ l) hl1).smul_right _ + +theorem detp_smul_add_adjp (hAB : A * B = 1) : + detp 1 B • A + adjp (-1) B = detp (-1) B • A + adjp 1 B := by + have key := congr(A * $(mul_adjp_add_detp B)) + simp_rw [mul_add, ← mul_assoc, hAB, one_mul, mul_smul, mul_one] at key + rwa [add_comm, eq_comm, add_comm] + +theorem detp_smul_adjp (hAB : A * B = 1) : + A + (detp 1 A • adjp (-1) B + detp (-1) A • adjp 1 B) = + detp 1 A • adjp 1 B + detp (-1) A • adjp (-1) B := by + have h0 := detp_mul A B + rw [hAB, detp_one_one, detp_neg_one_one, zero_add] at h0 + have h := detp_smul_add_adjp hAB + replace h := congr(detp 1 A • $h + detp (-1) A • $h.symm) + simp only [smul_add, smul_smul] at h + rwa [add_add_add_comm, ← add_smul, add_add_add_comm, ← add_smul, ← h0, add_smul, one_smul, + add_comm A, add_assoc, ((isAddUnit_detp_mul_detp hAB).smul_right _).add_right_inj] at h + +theorem mul_eq_one_comm : A * B = 1 ↔ B * A = 1 := by + suffices h : ∀ A B : Matrix n n R, A * B = 1 → B * A = 1 from ⟨h A B, h B A⟩ + intro A B hAB + have h0 := detp_mul A B + rw [hAB, detp_one_one, detp_neg_one_one, zero_add] at h0 + replace h := congr(B * $(detp_smul_adjp hAB)) + simp only [mul_add, mul_smul, add_assoc] at h + replace h := congr($h + (detp 1 A * detp (-1) B + detp (-1) A * detp 1 B) • 1) + simp_rw [add_smul, ← smul_smul] at h + rwa [add_assoc, add_add_add_comm, ← smul_add, ← smul_add, + add_add_add_comm, ← smul_add, ← smul_add, smul_add, smul_add, + mul_adjp_add_detp, smul_add, ← mul_adjp_add_detp, smul_add, ← smul_add, ← smul_add, + add_add_add_comm, smul_smul, smul_smul, ← add_smul, ← h0, + add_smul, one_smul, ← add_assoc _ 1, add_comm _ 1, add_assoc, + smul_add, smul_add, add_add_add_comm, smul_smul, smul_smul, ← add_smul, + ((isAddUnit_detp_smul_mul_adjp hAB).add + ((isAddUnit_detp_mul_detp hAB).smul_right _)).add_left_inj] at h + +variable (A B) + +/-- We can construct an instance of invertible A if A has a left inverse. -/ +def invertibleOfLeftInverse (h : B * A = 1) : Invertible A := + ⟨B, h, mul_eq_one_comm.mp h⟩ + +/-- We can construct an instance of invertible A if A has a right inverse. -/ +def invertibleOfRightInverse (h : A * B = 1) : Invertible A := + ⟨B, mul_eq_one_comm.mp h, h⟩ + +variable {A B} + +theorem isUnit_of_left_inverse (h : B * A = 1) : IsUnit A := + ⟨⟨A, B, mul_eq_one_comm.mp h, h⟩, rfl⟩ + +theorem exists_left_inverse_iff_isUnit : (∃ B, B * A = 1) ↔ IsUnit A := + ⟨fun ⟨_, h⟩ ↦ isUnit_of_left_inverse h, fun h ↦ have := h.invertible; ⟨⅟A, invOf_mul_self' A⟩⟩ + +theorem isUnit_of_right_inverse (h : A * B = 1) : IsUnit A := + ⟨⟨A, B, h, mul_eq_one_comm.mp h⟩, rfl⟩ + +theorem exists_right_inverse_iff_isUnit : (∃ B, A * B = 1) ↔ IsUnit A := + ⟨fun ⟨_, h⟩ ↦ isUnit_of_right_inverse h, fun h ↦ have := h.invertible; ⟨⅟A, mul_invOf_self' A⟩⟩ + +/-- A version of `mul_eq_one_comm` that works for square matrices with rectangular types. -/ +theorem mul_eq_one_comm_of_equiv {A : Matrix m n R} {B : Matrix n m R} (e : m ≃ n) : + A * B = 1 ↔ B * A = 1 := by + refine (reindex e e).injective.eq_iff.symm.trans ?_ + rw [reindex_apply, reindex_apply, submatrix_one_equiv, ← submatrix_mul_equiv _ _ _ (.refl _), + mul_eq_one_comm, submatrix_mul_equiv, coe_refl, submatrix_id_id] + +end Matrix diff --git a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean index d15dfc288b115..150f3e2f40e25 100644 --- a/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean +++ b/Mathlib/LinearAlgebra/Matrix/SesquilinearForm.lean @@ -563,7 +563,6 @@ theorem Matrix.isAdjointPair_equiv (P : Matrix n n R) (h : IsUnit P) : dsimp only [Matrix.IsAdjointPair] simp only [Matrix.transpose_mul] simp only [← mul_assoc, P.transpose_nonsing_inv] - -- Porting note: the previous proof used `conv` and was causing timeouts, so we use `convert` convert this using 2 · rw [mul_assoc, mul_assoc, ← mul_assoc J] rfl diff --git a/Mathlib/LinearAlgebra/Matrix/ToLin.lean b/Mathlib/LinearAlgebra/Matrix/ToLin.lean index 16a56b2c45728..de85599206032 100644 --- a/Mathlib/LinearAlgebra/Matrix/ToLin.lean +++ b/Mathlib/LinearAlgebra/Matrix/ToLin.lean @@ -9,6 +9,7 @@ import Mathlib.Data.Matrix.Block import Mathlib.Data.Matrix.Notation import Mathlib.LinearAlgebra.Matrix.StdBasis import Mathlib.RingTheory.AlgebraTower +import Mathlib.RingTheory.Ideal.Span /-! # Linear maps and matrices diff --git a/Mathlib/LinearAlgebra/Matrix/Transvection.lean b/Mathlib/LinearAlgebra/Matrix/Transvection.lean index 1c777ee3fb514..9b9593fe097ac 100644 --- a/Mathlib/LinearAlgebra/Matrix/Transvection.lean +++ b/Mathlib/LinearAlgebra/Matrix/Transvection.lean @@ -403,7 +403,7 @@ theorem listTransvecCol_mul_last_col (hM : M (inr unit) (inr unit) ≠ 0) (i : F have A : (listTransvecCol M)[n] = transvection (inl n') (inr unit) (-M (inl n') (inr unit) / M (inr unit) (inr unit)) := by - simp [listTransvecCol] + simp [n', listTransvecCol] simp only [Matrix.mul_assoc, A, List.prod_cons] by_cases h : n' = i · have hni : n = i := by @@ -416,7 +416,7 @@ theorem listTransvecCol_mul_last_col (hM : M (inr unit) (inr unit) ≠ 0) (i : F · have hni : n ≠ i := by rintro rfl cases i - simp at h + simp [n'] at h simp only [ne_eq, inl.injEq, Ne.symm h, not_false_eq_true, transvection_mul_apply_of_ne] rw [IH] rcases le_or_lt (n + 1) i with (hi | hi) @@ -441,7 +441,7 @@ theorem mul_listTransvecRow_last_col_take (i : Fin r ⊕ Unit) {k : ℕ} (hk : k (listTransvecRow M)[k]? = ↑(transvection (inr Unit.unit) (inl k') (-M (inr Unit.unit) (inl k') / M (inr Unit.unit) (inr Unit.unit))) := by - simp only [listTransvecRow, List.ofFnNthVal, hkr, dif_pos, List.getElem?_ofFn] + simp only [k', listTransvecRow, List.ofFnNthVal, hkr, dif_pos, List.getElem?_ofFn] simp only [List.take_succ, ← Matrix.mul_assoc, this, List.prod_append, Matrix.mul_one, List.prod_cons, List.prod_nil, Option.toList_some] rw [mul_transvection_apply_of_ne, IH hkr.le] @@ -476,7 +476,7 @@ theorem mul_listTransvecRow_last_row (hM : M (inr unit) (inr unit) ≠ 0) (i : F (listTransvecRow M)[n]? = ↑(transvection (inr unit) (inl n') (-M (inr unit) (inl n') / M (inr unit) (inr unit))) := by - simp only [listTransvecRow, List.ofFnNthVal, hnr, dif_pos, List.getElem?_ofFn] + simp only [n', listTransvecRow, List.ofFnNthVal, hnr, dif_pos, List.getElem?_ofFn] simp only [List.take_succ, A, ← Matrix.mul_assoc, List.prod_append, Matrix.mul_one, List.prod_cons, List.prod_nil, Option.toList_some] by_cases h : n' = i diff --git a/Mathlib/LinearAlgebra/PID.lean b/Mathlib/LinearAlgebra/PID.lean index 77090d78d128c..9c332cd59b756 100644 --- a/Mathlib/LinearAlgebra/PID.lean +++ b/Mathlib/LinearAlgebra/PID.lean @@ -41,6 +41,6 @@ lemma trace_restrict_eq_of_forall_mem [IsDomain R] [IsPrincipalIdealRing R] contrapose! hi; exact snf.repr_eq_zero_of_nmem_range ⟨_, (hf _)⟩ hi change ∑ i, A i i = ∑ i, B i i rw [← Finset.sum_filter_of_ne (p := fun j ↦ j ∈ Set.range snf.f) (by simpa using aux)] - simp [A] + simp [A, B] end LinearMap diff --git a/Mathlib/LinearAlgebra/PerfectPairing.lean b/Mathlib/LinearAlgebra/PerfectPairing.lean index ca394d510fa52..78fff41b7e142 100644 --- a/Mathlib/LinearAlgebra/PerfectPairing.lean +++ b/Mathlib/LinearAlgebra/PerfectPairing.lean @@ -165,6 +165,23 @@ include p in theorem reflexive_right : IsReflexive R N := p.flip.reflexive_left +instance : EquivLike (PerfectPairing R M N) M (Dual R N) where + coe p := p.toDualLeft + inv p := p.toDualLeft.symm + left_inv p x := LinearEquiv.symm_apply_apply _ _ + right_inv p x := LinearEquiv.apply_symm_apply _ _ + coe_injective' p q h h' := by + cases p + cases q + simp only [mk.injEq] + ext m n + simp only [DFunLike.coe_fn_eq] at h + exact LinearMap.congr_fun (LinearEquiv.congr_fun h m) n + +instance : LinearEquivClass (PerfectPairing R M N) R M (Dual R N) where + map_add p m₁ m₂ := p.toLin.map_add m₁ m₂ + map_smulₛₗ p t m := p.toLin.map_smul t m + include p in theorem finrank_eq [Module.Finite R M] [Module.Free R M] : finrank R M = finrank R N := @@ -244,11 +261,11 @@ lemma exists_basis_basis_of_span_eq_top_of_mem_algebraMap suffices span K (Set.range v') = ⊤ by let e := (Module.Finite.finite_basis b).equivFin let b' : Basis _ K M' := Basis.mk hv' (by rw [this]) - exact ⟨_, b.reindex e, b'.reindex e, fun i ↦ by simp [b, b']⟩ + exact ⟨_, b.reindex e, b'.reindex e, fun i ↦ by simp [b, b', v']⟩ suffices span K v = M' by apply Submodule.map_injective_of_injective M'.injective_subtype rw [Submodule.map_span, ← Set.image_univ, Set.image_image] - simpa + simpa [v'] refine le_antisymm (Submodule.span_le.mpr hv₁) fun m hm ↦ ?_ obtain ⟨w, hw₁, hw₂, hw₃⟩ := exists_linearIndependent L (N' : Set N) rw [hN] at hw₂ @@ -265,7 +282,7 @@ lemma exists_basis_basis_of_span_eq_top_of_mem_algebraMap toDualLeft_apply, Basis.dualBasis_repr] exact hp (b j) (by simpa [b] using hv₁ j.2) (bN i) (by simpa [bN] using hw₁ i.2) have hA (i j) : b.toMatrix bM i j ∈ (algebraMap K L).range := - Matrix.mem_subfield_of_mul_eq_one_of_mem_subfield_left e _ (by simp) hp i j + Matrix.mem_subfield_of_mul_eq_one_of_mem_subfield_left e _ (by simp [bM]) hp i j have h_span : span K v = span K (Set.range b) := by simp [b] rw [h_span, Basis.mem_span_iff_repr_mem, ← Basis.toMatrix_mulVec_repr bM b m] exact fun i ↦ Subring.sum_mem _ fun j _ ↦ Subring.mul_mem _ (hA i j) (hj j) diff --git a/Mathlib/LinearAlgebra/Prod.lean b/Mathlib/LinearAlgebra/Prod.lean index 23732c0a35284..8aa773428cf39 100644 --- a/Mathlib/LinearAlgebra/Prod.lean +++ b/Mathlib/LinearAlgebra/Prod.lean @@ -76,6 +76,10 @@ theorem fst_apply (x : M × M₂) : fst R M M₂ x = x.1 := theorem snd_apply (x : M × M₂) : snd R M M₂ x = x.2 := rfl +@[simp, norm_cast] lemma coe_fst : ⇑(fst R M M₂) = Prod.fst := rfl + +@[simp, norm_cast] lemma coe_snd : ⇑(snd R M M₂) = Prod.snd := rfl + theorem fst_surjective : Function.Surjective (fst R M M₂) := fun x => ⟨(x, 0), rfl⟩ theorem snd_surjective : Function.Surjective (snd R M M₂) := fun x => ⟨(0, x), rfl⟩ @@ -830,8 +834,7 @@ variable {N : Type*} [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] open Function -set_option linter.deprecated false - +set_option linter.deprecated false in /-- An auxiliary construction for `tunnel`. The composition of `f`, followed by the isomorphism back to `K`, followed by the inclusion of this submodule back into `M`. -/ @@ -839,11 +842,13 @@ followed by the inclusion of this submodule back into `M`. -/ def tunnelAux (f : M × N →ₗ[R] M) (Kφ : ΣK : Submodule R M, K ≃ₗ[R] M) : M × N →ₗ[R] M := (Kφ.1.subtype.comp Kφ.2.symm.toLinearMap).comp f +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tunnelAux_injective (f : M × N →ₗ[R] M) (i : Injective f) (Kφ : ΣK : Submodule R M, K ≃ₗ[R] M) : Injective (tunnelAux f Kφ) := (Subtype.val_injective.comp Kφ.2.symm.injective).comp i +set_option linter.deprecated false in /-- Auxiliary definition for `tunnel`. -/ @[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tunnel' (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → ΣK : Submodule R M, K ≃ₗ[R] M @@ -853,6 +858,7 @@ def tunnel' (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → ΣK : Submodule ((Submodule.fst R M N).equivMapOfInjective _ (tunnelAux_injective f i (tunnel' f i n))).symm.trans (Submodule.fstEquiv R M N)⟩ +set_option linter.deprecated false in /-- Give an injective map `f : M × N →ₗ[R] M` we can find a nested sequence of submodules all isomorphic to `M`. -/ @@ -865,6 +871,7 @@ def tunnel (f : M × N →ₗ[R] M) (i : Injective f) : ℕ →o (Submodule R M) rw [Submodule.map_comp, Submodule.map_comp] apply Submodule.map_subtype_le⟩ +set_option linter.deprecated false in /-- Give an injective map `f : M × N →ₗ[R] M` we can find a sequence of submodules all isomorphic to `N`. -/ @@ -872,12 +879,14 @@ all isomorphic to `N`. def tailing (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Submodule R M := (Submodule.snd R M N).map (tunnelAux f (tunnel' f i n)) +set_option linter.deprecated false in /-- Each `tailing f i n` is a copy of `N`. -/ @[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tailingLinearEquiv (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ≃ₗ[R] N := ((Submodule.snd R M N).equivMapOfInjective _ (tunnelAux_injective f i (tunnel' f i n))).symm.trans (Submodule.sndEquiv R M N) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ≤ OrderDual.ofDual (α := Submodule R M) (tunnel f i n) := by @@ -885,6 +894,7 @@ theorem tailing_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : rw [Submodule.map_comp, Submodule.map_comp] apply Submodule.map_subtype_le +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailing f i n) (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) := by @@ -894,6 +904,7 @@ theorem tailing_disjoint_tunnel_succ (f : M × N →ₗ[R] M) (i : Injective f) Submodule.comap_map_eq_of_injective (tunnelAux_injective _ i _), inf_comm, Submodule.fst_inf_snd, Submodule.map_bot] +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailing f i n ⊔ (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) ≤ @@ -902,19 +913,23 @@ theorem tailing_sup_tunnel_succ_le_tunnel (f : M × N →ₗ[R] M) (i : Injectiv rw [← Submodule.map_sup, sup_comm, Submodule.fst_sup_snd, Submodule.map_comp, Submodule.map_comp] apply Submodule.map_subtype_le +set_option linter.deprecated false in /-- The supremum of all the copies of `N` found inside the tunnel. -/ @[deprecated "No deprecation message was provided." (since := "2024-06-05")] def tailings (f : M × N →ₗ[R] M) (i : Injective f) : ℕ → Submodule R M := partialSups (tailing f i) +set_option linter.deprecated false in @[simp, deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_zero (f : M × N →ₗ[R] M) (i : Injective f) : tailings f i 0 = tailing f i 0 := by simp [tailings] +set_option linter.deprecated false in @[simp, deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_succ (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : tailings f i (n + 1) = tailings f i n ⊔ tailing f i (n + 1) := by simp [tailings] +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailings f i n) (OrderDual.ofDual (α := Submodule R M) <| tunnel f i (n + 1)) := by @@ -927,6 +942,7 @@ theorem tailings_disjoint_tunnel (f : M × N →ₗ[R] M) (i : Injective f) (n : · apply Disjoint.mono_right _ ih apply tailing_sup_tunnel_succ_le_tunnel +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-06-05")] theorem tailings_disjoint_tailing (f : M × N →ₗ[R] M) (i : Injective f) (n : ℕ) : Disjoint (tailings f i n) (tailing f i (n + 1)) := @@ -985,7 +1001,8 @@ most once. Then the image of `f` is the graph of some linear map `f' : H → I`. lemma LinearMap.exists_range_eq_graph {f : G →ₛₗ[σ] H × I} (hf₁ : Surjective (Prod.fst ∘ f)) (hf : ∀ g₁ g₂, (f g₁).1 = (f g₂).1 → (f g₁).2 = (f g₂).2) : ∃ f' : H →ₗ[S] I, LinearMap.range f = LinearMap.graph f' := by - obtain ⟨f', hf'⟩ := AddMonoidHom.exists_mrange_eq_mgraph (I := I) (f := f) hf₁ hf + obtain ⟨f', hf'⟩ := + AddMonoidHom.exists_mrange_eq_mgraph (G := G) (H := H) (I := I) (f := f) hf₁ hf simp only [SetLike.ext_iff, AddMonoidHom.mem_mrange, AddMonoidHom.coe_coe, AddMonoidHom.mem_mgraph] at hf' use diff --git a/Mathlib/LinearAlgebra/Projectivization/Constructions.lean b/Mathlib/LinearAlgebra/Projectivization/Constructions.lean index fd7470292b540..cdbb83b605a70 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Constructions.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Constructions.lean @@ -67,7 +67,7 @@ variable [DecidableEq F] /-- Cross product on the projective plane. -/ def cross : ℙ F (Fin 3 → F) → ℙ F (Fin 3 → F) → ℙ F (Fin 3 → F) := - Quotient.map₂' (fun v w ↦ if h : crossProduct v.1 w.1 = 0 then v else ⟨crossProduct v.1 w.1, h⟩) + Quotient.map₂ (fun v w ↦ if h : crossProduct v.1 w.1 = 0 then v else ⟨crossProduct v.1 w.1, h⟩) (fun _ _ ⟨a, ha⟩ _ _ ⟨b, hb⟩ ↦ by simp_rw [← ha, ← hb, LinearMap.map_smul_of_tower, LinearMap.smul_apply, smul_smul, mul_comm b a, smul_eq_zero_iff_eq] diff --git a/Mathlib/LinearAlgebra/Projectivization/Subspace.lean b/Mathlib/LinearAlgebra/Projectivization/Subspace.lean index 2ae201b95720b..b0a0703432616 100644 --- a/Mathlib/LinearAlgebra/Projectivization/Subspace.lean +++ b/Mathlib/LinearAlgebra/Projectivization/Subspace.lean @@ -154,6 +154,9 @@ span of that set. -/ theorem monotone_span : Monotone (span : Set (ℙ K V) → Subspace K V) := gi.gc.monotone_l +@[gcongr] +lemma span_le_span {s t : Set (ℙ K V)} (hst : s ⊆ t) : span s ≤ span t := monotone_span hst + theorem subset_span_trans {S T U : Set (ℙ K V)} (hST : S ⊆ span T) (hTU : T ⊆ span U) : S ⊆ span U := gi.gc.le_u_l_trans hST hTU diff --git a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean index 7e6c8fa28492e..5d6cf88a2bfcf 100644 --- a/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean +++ b/Mathlib/LinearAlgebra/QuadraticForm/QuadraticModuleCat.lean @@ -37,8 +37,9 @@ instance : CoeSort (QuadraticModuleCat.{v} R) (Type v) := /-- The object in the category of quadratic R-modules associated to a quadratic R-module. -/ @[simps form] def of {X : Type v} [AddCommGroup X] [Module R X] (Q : QuadraticForm R X) : - QuadraticModuleCat R where - form := Q + QuadraticModuleCat R := + { ModuleCat.of R X with + form := Q } /-- A type alias for `QuadraticForm.LinearIsometry` to avoid confusion between the categorical and algebraic spellings of composition. -/ @@ -89,7 +90,7 @@ instance concreteCategory : ConcreteCategory.{v} (QuadraticModuleCat.{v} R) wher instance hasForgetToModule : HasForget₂ (QuadraticModuleCat R) (ModuleCat R) where forget₂ := { obj := fun M => ModuleCat.of R M - map := fun f => f.toIsometry.toLinearMap } + map := fun f => ModuleCat.ofHom f.toIsometry.toLinearMap } @[simp] theorem forget₂_obj (X : QuadraticModuleCat R) : @@ -98,7 +99,8 @@ theorem forget₂_obj (X : QuadraticModuleCat R) : @[simp] theorem forget₂_map (X Y : QuadraticModuleCat R) (f : X ⟶ Y) : - (forget₂ (QuadraticModuleCat R) (ModuleCat R)).map f = f.toIsometry.toLinearMap := + (forget₂ (QuadraticModuleCat R) (ModuleCat R)).map f = + ModuleCat.ofHom f.toIsometry.toLinearMap := rfl variable {X Y Z : Type v} diff --git a/Mathlib/LinearAlgebra/Reflection.lean b/Mathlib/LinearAlgebra/Reflection.lean index d807bcfeec42e..73d856bbbc9eb 100644 --- a/Mathlib/LinearAlgebra/Reflection.lean +++ b/Mathlib/LinearAlgebra/Reflection.lean @@ -1,12 +1,14 @@ /- Copyright (c) 2023 Oliver Nash. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Oliver Nash, Deepro Choudhury +Authors: Oliver Nash, Deepro Choudhury, Mitchell Lee, Johan Commelin -/ import Mathlib.Algebra.Module.LinearMap.Basic import Mathlib.GroupTheory.OrderOfElement import Mathlib.LinearAlgebra.Dual import Mathlib.LinearAlgebra.FiniteSpan +import Mathlib.RingTheory.Polynomial.Chebyshev +import Mathlib.Algebra.Module.Torsion /-! # Reflections in linear algebra @@ -28,6 +30,9 @@ is characterised by properties 1 and 2 above, and is a linear isometry. * `Module.reflection`: the definition of the map `y ↦ y - (f y) • x`. This requires the assumption that `f x = 2` but by way of compensation it produces a linear equivalence rather than a mere linear map. + * `Module.reflection_mul_reflection_pow_apply`: a formula for $(r_1 r_2)^m z$, where $r_1$ and + $r_2$ are reflections and $z \in M$. It involves the Chebyshev polynomials and holds over any + commutative ring. This is used to define reflection representations of Coxeter groups. * `Module.Dual.eq_of_preReflection_mapsTo`: a uniqueness result about reflections preserving finite spanning sets that is useful in the theory of root data / systems. @@ -101,6 +106,9 @@ lemma involutive_reflection (h : f x = 2) : Involutive (reflection h) := involutive_preReflection h +@[simp] +lemma reflection_inv (h : f x = 2) : (reflection h)⁻¹ = reflection h := rfl + @[simp] lemma reflection_symm (h : f x = 2) : (reflection h).symm = reflection h := @@ -114,6 +122,194 @@ lemma bijOn_reflection_of_mapsTo {Φ : Set M} (h : f x = 2) (h' : MapsTo (reflec BijOn (reflection h) Φ Φ := (invOn_reflection_of_mapsTo h).bijOn h' h' +/-! ### Powers of the product of two reflections + +Let $M$ be a module over a commutative ring $R$. Let $x, y \in M$ and $f, g \in M^*$ with +$f(x) = g(y) = 2$. The corresponding reflections $r_1, r_2 \colon M \to M$ (`Module.reflection`) are +given by $r_1z = z - f(z) x$ and $r_2 z = z - g(z) y$. These are linear automorphisms of $M$. + +To define reflection representations of a Coxeter group, it is important to be able to compute the +order of the composition $r_1 r_2$. + +Note that if $M$ is a real inner product space and $r_1$ and $r_2$ are both orthogonal +reflections (i.e. $f(z) = 2 \langle x, z \rangle / \langle x, x \rangle$ and +$g(z) = 2 \langle y, z\rangle / \langle y, y\rangle$ for all $z \in M$), +then $r_1 r_2$ is a rotation by the angle +$$\cos^{-1}\left(\frac{f(y) g(x) - 2}{2}\right)$$ +and one may determine the order of $r_1 r_2$ accordingly. + +However, if $M$ does not have an inner product, and even if $R$ is not $\mathbb{R}$, then we may +instead use the formulas in this section. These formulas all involve evaluating Chebyshev +$S$-polynomials (`Polynomial.Chebyshev.S`) at $t = f(y) g(x) - 2$, and they hold over any +commutative ring. -/ +section + +open Int Polynomial.Chebyshev + +variable {x y : M} {f g : Dual R M} (hf : f x = 2) (hg : g y = 2) + +/-- A formula for $(r_1 r_2)^m z$, where $m$ is a natural number and $z \in M$. -/ +lemma reflection_mul_reflection_pow_apply (m : ℕ) (z : M) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m) z = + z + + ((S R ((m - 2) / 2)).eval t * ((S R ((m - 1) / 2)).eval t + (S R ((m - 3) / 2)).eval t)) • + ((g x * f z - g z) • y - f z • x) + + ((S R ((m - 1) / 2)).eval t * ((S R (m / 2)).eval t + (S R ((m - 2) / 2)).eval t)) • + ((f y * g z - f z) • x - g z • y) := by + induction m with + | zero => simp + | succ m ih => + /- Now, let us collect two facts about the evaluations of `S r k`. These easily follow from the + properties of the `S` polynomials. -/ + have S_eval_t_sub_two (k : ℤ) : + (S R (k - 2)).eval t = t * (S R (k - 1)).eval t - (S R k).eval t := by + simp [S_sub_two] + have S_eval_t_sq_add_S_eval_t_sq (k : ℤ) : + (S R k).eval t ^ 2 + (S R (k + 1)).eval t ^ 2 - t * (S R k).eval t * (S R (k + 1)).eval t + = 1 := by + simpa using congr_arg (Polynomial.eval t) (S_sq_add_S_sq R k) + -- Apply the inductive hypothesis. + rw [pow_succ', LinearEquiv.mul_apply, ih, LinearEquiv.mul_apply] + -- Expand out all the reflections and use `hf`, `hg`. + simp only [reflection_apply, map_add, map_sub, map_smul, hf, hg] + -- `m` can be written in the form `2 * k + e`, where `e` is `0` or `1`. + push_cast + set k : ℤ := m / 2 + set e : ℤ := m % 2 + rw [show m = 2 * k + e from (Int.ediv_add_emod m 2).symm] + simp_rw [add_assoc (2 * k), add_sub_assoc (2 * k), add_comm (2 * k), + add_mul_ediv_left _ k (by norm_num : (2 : ℤ) ≠ 0)] + have he : e = 0 ∨ e = 1 := by omega + clear_value e + /- Now, equate the coefficients on both sides. These linear combinations were + found using `polyrith`. -/ + match_scalars + · rfl + · linear_combination (norm := skip) (-g z * f y * (S R (e - 1 + k)).eval t + + f z * (S R (e - 1 + k)).eval t) * S_eval_t_sub_two (e + k) + + (-g z * f y + f z) * S_eval_t_sq_add_S_eval_t_sq (k - 1) + subst ht + obtain rfl | rfl : e = 0 ∨ e = 1 := he <;> ring_nf + · linear_combination (norm := skip) + g z * (S R (e - 1 + k)).eval t * S_eval_t_sub_two (e + k) + + g z * S_eval_t_sq_add_S_eval_t_sq (k - 1) + subst ht + obtain rfl | rfl : e = 0 ∨ e = 1 := he <;> ring_nf + +/-- A formula for $(r_1 r_2)^m$, where $m$ is a natural number. -/ +lemma reflection_mul_reflection_pow (m : ℕ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m).toLinearMap = + LinearMap.id (R := R) (M := M) + + ((S R ((m - 2) / 2)).eval t * ((S R ((m - 1) / 2)).eval t + (S R ((m - 3) / 2)).eval t)) • + ((g x • f - g).smulRight y - f.smulRight x) + + ((S R ((m - 1) / 2)).eval t * ((S R (m / 2)).eval t + (S R ((m - 2) / 2)).eval t)) • + ((f y • g - f).smulRight x - g.smulRight y) := by + ext z + simpa using reflection_mul_reflection_pow_apply hf hg m z t ht + +/-- A formula for $(r_1 r_2)^m z$, where $m$ is an integer and $z \in M$. -/ +lemma reflection_mul_reflection_zpow_apply (m : ℤ) (z : M) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m) z = + z + + ((S R ((m - 2) / 2)).eval t * ((S R ((m - 1) / 2)).eval t + (S R ((m - 3) / 2)).eval t)) • + ((g x * f z - g z) • y - f z • x) + + ((S R ((m - 1) / 2)).eval t * ((S R (m / 2)).eval t + (S R ((m - 2) / 2)).eval t)) • + ((f y * g z - f z) • x - g z • y) := by + induction m using Int.negInduction with + | nat m => exact_mod_cast reflection_mul_reflection_pow_apply hf hg m z t ht + | neg _ m => + have ht' : t = g x * f y - 2 := by rwa [mul_comm (g x)] + rw [zpow_neg, ← inv_zpow, mul_inv_rev, reflection_inv, reflection_inv, zpow_natCast, + reflection_mul_reflection_pow_apply hg hf m z t ht', add_right_comm z] + have aux {a b : ℤ} (hab : a + b = -3) : a / 2 = -(b / 2) - 2 := by + rw [← mul_right_inj' (by norm_num : (2 : ℤ) ≠ 0), mul_sub, mul_neg, + eq_sub_of_add_eq (Int.ediv_add_emod _ _), eq_sub_of_add_eq (Int.ediv_add_emod _ _)] + omega + rw [aux (by omega : (-m - 3) + m = (-3 : ℤ)), + aux (by omega : (-m - 2) + (m - 1) = (-3 : ℤ)), + aux (by omega : (-m - 1) + (m - 2) = (-3 : ℤ)), + aux (by omega : -m + (m - 3) = (-3 : ℤ))] + simp only [S_neg_sub_two, Polynomial.eval_neg] + ring_nf + +/-- A formula for $(r_1 r_2)^m$, where $m$ is an integer. -/ +lemma reflection_mul_reflection_zpow (m : ℤ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m).toLinearMap = + LinearMap.id (R := R) (M := M) + + ((S R ((m - 2) / 2)).eval t * ((S R ((m - 1) / 2)).eval t + (S R ((m - 3) / 2)).eval t)) • + ((g x • f - g).smulRight y - f.smulRight x) + + ((S R ((m - 1) / 2)).eval t * ((S R (m / 2)).eval t + (S R ((m - 2) / 2)).eval t)) • + ((f y • g - f).smulRight x - g.smulRight y) := by + ext z + simpa using reflection_mul_reflection_zpow_apply hf hg m z t ht + +/-- A formula for $(r_1 r_2)^m x$, where $m$ is an integer. This is the special case of +`Module.reflection_mul_reflection_zpow_apply` with $z = x$. -/ +lemma reflection_mul_reflection_zpow_apply_self (m : ℤ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m) x = + ((S R m).eval t + (S R (m - 1)).eval t) • x + ((S R (m - 1)).eval t * -g x) • y := by + /- Even though this is a special case of `Module.reflection_mul_reflection_zpow_apply`, it is + easier to prove it from scratch. -/ + have S_eval_t_sub_two (k : ℤ) : + (S R (k - 2)).eval t = (f y * g x - 2) * (S R (k - 1)).eval t - (S R k).eval t := by + simp [S_sub_two, ht] + induction m using Int.induction_on with + | hz => simp + | hp m ih => + -- Apply the inductive hypothesis. + rw [add_comm (m : ℤ) 1, zpow_one_add, LinearEquiv.mul_apply, LinearEquiv.mul_apply, ih] + -- Expand out all the reflections and use `hf`, `hg`. + simp only [reflection_apply, map_add, map_sub, map_smul, hf, hg] + -- Equate coefficients of `x` and `y`. + match_scalars + · linear_combination (norm := ring_nf) -S_eval_t_sub_two (m + 1) + · ring_nf + | hn m ih => + -- Apply the inductive hypothesis. + rw [sub_eq_add_neg (-m : ℤ) 1, add_comm (-m : ℤ) (-1), zpow_add, zpow_neg_one, mul_inv_rev, + reflection_inv, reflection_inv, LinearEquiv.mul_apply, LinearEquiv.mul_apply, ih] + -- Expand out all the reflections and use `hf`, `hg`. + simp only [reflection_apply, map_add, map_sub, map_smul, hf, hg] + -- Equate coefficients of `x` and `y`. + match_scalars + · linear_combination (norm := ring_nf) -S_eval_t_sub_two (-m) + · linear_combination (norm := ring_nf) g x * S_eval_t_sub_two (-m) + +/-- A formula for $(r_1 r_2)^m x$, where $m$ is a natural number. This is the special case of +`Module.reflection_mul_reflection_pow_apply` with $z = x$. -/ +lemma reflection_mul_reflection_pow_apply_self (m : ℕ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + ((reflection hf * reflection hg) ^ m) x = + ((S R m).eval t + (S R (m - 1)).eval t) • x + ((S R (m - 1)).eval t * -g x) • y := + mod_cast reflection_mul_reflection_zpow_apply_self hf hg m t ht + +/-- A formula for $r_2 (r_1 r_2)^m x$, where $m$ is an integer. -/ +lemma reflection_mul_reflection_mul_reflection_zpow_apply_self (m : ℤ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + (reflection hg * (reflection hf * reflection hg) ^ m) x = + ((S R m).eval t + (S R (m - 1)).eval t) • x + ((S R m).eval t * -g x) • y := by + rw [LinearEquiv.mul_apply, reflection_mul_reflection_zpow_apply_self hf hg m t ht] + -- Expand out all the reflections and use `hf`, `hg`. + simp only [reflection_apply, map_add, map_sub, map_smul, hf, hg] + -- Equate coefficients of `x` and `y`. + module + +/-- A formula for $r_2 (r_1 r_2)^m x$, where $m$ is a natural number. -/ +lemma reflection_mul_reflection_mul_reflection_pow_apply_self (m : ℕ) + (t : R := f y * g x - 2) (ht : t = f y * g x - 2 := by rfl) : + (reflection hg * (reflection hf * reflection hg) ^ m) x = + ((S R m).eval t + (S R (m - 1)).eval t) • x + ((S R m).eval t * -g x) • y := + mod_cast reflection_mul_reflection_mul_reflection_zpow_apply_self hf hg m t ht + +end + +/-! ### Lemmas used to prove uniqueness results for root data -/ + /-- See also `Module.Dual.eq_of_preReflection_mapsTo'` for a variant of this lemma which applies when `Φ` does not span. diff --git a/Mathlib/LinearAlgebra/RootSystem/Basic.lean b/Mathlib/LinearAlgebra/RootSystem/Basic.lean index 4aba11c944d5e..ba9290e8307a8 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Basic.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Basic.lean @@ -73,7 +73,7 @@ protected def equiv_of_mapsTo : end reflection_perm -lemma infinite_of_linearly_independent_coxeterWeight_four [CharZero R] [NoZeroSMulDivisors ℤ M] +lemma infinite_of_linearIndependent_coxeterWeight_four [CharZero R] [NoZeroSMulDivisors ℤ M] (P : RootPairing ι R M N) (i j : ι) (hl : LinearIndependent R ![P.root i, P.root j]) (hc : P.coxeterWeight i j = 4) : Infinite ι := by refine (infinite_range_iff (Embedding.injective P.root)).mp (Infinite.mono ?_ @@ -94,6 +94,13 @@ lemma infinite_of_linearly_independent_coxeterWeight_four [CharZero R] [NoZeroSM variable [Finite ι] (P : RootPairing ι R M N) (i j : ι) +lemma coxeterWeight_ne_four_of_linearIndependent [CharZero R] [NoZeroSMulDivisors ℤ M] + (hl : LinearIndependent R ![P.root i, P.root j]) : + P.coxeterWeight i j ≠ 4 := by + intro contra + have := P.infinite_of_linearIndependent_coxeterWeight_four i j hl contra + exact not_finite ι + /-- Even though the roots may not span, coroots are distinguished by their pairing with the roots. The proof depends crucially on the fact that there are finitely-many roots. @@ -161,7 +168,8 @@ private lemma coroot_eq_coreflection_of_root_eq' [CharZero R] [NoZeroSMulDivisor rw [← hl] have hkl : (p.flip (coroot l)) (root k) = 2 := by simp only [hl, preReflection_apply, hk, PerfectPairing.flip_apply_apply, map_sub, hp j, - map_smul, smul_eq_mul, hp i, mul_sub, sα, α, α', β, mul_two, mul_add] + map_smul, smul_eq_mul, hp i, mul_sub, sα, α, α', β, mul_two, mul_add, LinearMap.sub_apply, + LinearMap.smul_apply] rw [mul_comm (p (root i) (coroot j))] abel suffices p.flip (coroot k) = p.flip (coroot l) from p.bijectiveRight.injective this diff --git a/Mathlib/LinearAlgebra/RootSystem/Defs.lean b/Mathlib/LinearAlgebra/RootSystem/Defs.lean index d9ab0eb932455..39c9941d22e0f 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Defs.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Defs.lean @@ -92,7 +92,11 @@ structure RootPairing extends PerfectPairing R M N where /-- A parametrized family of dual vectors, called coroots. -/ coroot : ι ↪ N root_coroot_two : ∀ i, toLin (root i) (coroot i) = 2 - /-- A parametrized family of permutations, induced by reflection. -/ + /-- A parametrized family of permutations, induced by reflections. This corresponds to the + classical requirement that the symmetry attached to each root (later defined in + `RootPairing.reflection`) leave the whole set of roots stable: as explained above, we + formalize this stability by fixing the image of the roots through each reflection (whence the + permutation); and similarly for coroots. -/ reflection_perm : ι → (ι ≃ ι) reflection_perm_root : ∀ i j, root j - toPerfectPairing (root j) (coroot i) • root i = root (reflection_perm i j) @@ -349,15 +353,20 @@ lemma pairing_reflection_perm_self_right (i j : ι) : /-- A root pairing is said to be crystallographic if the pairing between a root and coroot is always an integer. -/ -def IsCrystallographic : Prop := - ∀ i, MapsTo (P.root' i) (range P.coroot) (zmultiples (1 : R)) +class IsCrystallographic : Prop where + exists_int : ∀ i j, ∃ z : ℤ, z = P.pairing i j + +protected lemma exists_int [P.IsCrystallographic] (i j : ι) : + ∃ z : ℤ, z = P.pairing i j := + IsCrystallographic.exists_int i j lemma isCrystallographic_iff : - P.IsCrystallographic ↔ ∀ i j, ∃ z : ℤ, z = P.pairing i j := by - rw [IsCrystallographic] - refine ⟨fun h i j ↦ ?_, fun h i _ ⟨j, hj⟩ ↦ ?_⟩ - · simpa [AddSubgroup.mem_zmultiples_iff] using h i (mem_range_self j) - · simpa [← hj, AddSubgroup.mem_zmultiples_iff] using h i j + P.IsCrystallographic ↔ ∀ i j, ∃ z : ℤ, z = P.pairing i j := + ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + +instance [P.IsCrystallographic] : P.flip.IsCrystallographic := by + rw [isCrystallographic_iff, forall_comm] + exact P.exists_int /-- A root pairing is said to be reduced if any linearly dependent pair of roots is related by a sign. -/ @@ -380,13 +389,29 @@ abbrev rootSpan := span R (range P.root) /-- The linear span of coroots. -/ abbrev corootSpan := span R (range P.coroot) -/-- The `Weyl group` of a root pairing is the group of automorphisms of the weight space generated -by reflections in roots. -/ -def weylGroup : Subgroup (M ≃ₗ[R] M) := - Subgroup.closure (range P.reflection) +lemma coe_rootSpan_dualAnnihilator_map : + P.rootSpan.dualAnnihilator.map P.toDualRight.symm = {x | ∀ i, P.root' i x = 0} := by + ext x + rw [rootSpan, Submodule.map_coe, Submodule.coe_dualAnnihilator_span] + change x ∈ P.toDualRight.toEquiv.symm '' _ ↔ _ + rw [← Equiv.setOf_apply_symm_eq_image_setOf, Equiv.symm_symm] + simp [Set.range_subset_iff] + +lemma coe_corootSpan_dualAnnihilator_map : + P.corootSpan.dualAnnihilator.map P.toDualLeft.symm = {x | ∀ i, P.coroot' i x = 0} := + P.flip.coe_rootSpan_dualAnnihilator_map + +lemma rootSpan_dualAnnihilator_map_eq : + P.rootSpan.dualAnnihilator.map P.toDualRight.symm = + (span R (range P.root')).dualCoannihilator := by + apply SetLike.coe_injective + rw [Submodule.coe_dualCoannihilator_span, coe_rootSpan_dualAnnihilator_map] + simp -lemma reflection_mem_weylGroup : P.reflection i ∈ P.weylGroup := - Subgroup.subset_closure <| mem_range_self i +lemma corootSpan_dualAnnihilator_map_eq : + P.corootSpan.dualAnnihilator.map P.toDualLeft.symm = + (span R (range P.coroot')).dualCoannihilator := + P.flip.rootSpan_dualAnnihilator_map_eq lemma mem_range_root_of_mem_range_reflection_of_mem_range_root {r : M ≃ₗ[R] M} {α : M} (hr : r ∈ range P.reflection) (hα : α ∈ range P.root) : @@ -402,71 +427,6 @@ lemma mem_range_coroot_of_mem_range_coreflection_of_mem_range_coroot obtain ⟨j, rfl⟩ := hα exact ⟨P.reflection_perm i j, P.coroot_reflection_perm i j⟩ -lemma exists_root_eq_smul_of_mem_weylGroup {w : M ≃ₗ[R] M} (hw : w ∈ P.weylGroup) (i : ι) : - ∃ j, P.root j = w • P.root i := - Subgroup.smul_mem_of_mem_closure_of_mem (by simp) - (fun _ h _ ↦ P.mem_range_root_of_mem_range_reflection_of_mem_range_root h) hw (mem_range_self i) - -/-- The permutation representation of the Weyl group induced by `reflection_perm`. -/ -def weylGroupToPerm : P.weylGroup →* Equiv.Perm ι where - toFun w := - { toFun := fun i => (P.exists_root_eq_smul_of_mem_weylGroup w.2 i).choose - invFun := fun i => (P.exists_root_eq_smul_of_mem_weylGroup w⁻¹.2 i).choose - left_inv := fun i => by - obtain ⟨w, hw⟩ := w - apply P.root.injective - rw [(P.exists_root_eq_smul_of_mem_weylGroup ((Subgroup.inv_mem_iff P.weylGroup).mpr hw) - ((P.exists_root_eq_smul_of_mem_weylGroup hw i).choose)).choose_spec, - (P.exists_root_eq_smul_of_mem_weylGroup hw i).choose_spec, inv_smul_smul] - right_inv := fun i => by - obtain ⟨w, hw⟩ := w - have hw' : w⁻¹ ∈ P.weylGroup := (Subgroup.inv_mem_iff P.weylGroup).mpr hw - apply P.root.injective - rw [(P.exists_root_eq_smul_of_mem_weylGroup hw - ((P.exists_root_eq_smul_of_mem_weylGroup hw' i).choose)).choose_spec, - (P.exists_root_eq_smul_of_mem_weylGroup hw' i).choose_spec, smul_inv_smul] } - map_one' := by ext; simp - map_mul' x y := by - obtain ⟨x, hx⟩ := x - obtain ⟨y, hy⟩ := y - ext i - apply P.root.injective - simp only [Equiv.coe_fn_mk, Equiv.Perm.coe_mul, comp_apply] - rw [(P.exists_root_eq_smul_of_mem_weylGroup (mul_mem hx hy) i).choose_spec, - (P.exists_root_eq_smul_of_mem_weylGroup hx - ((P.exists_root_eq_smul_of_mem_weylGroup hy i).choose)).choose_spec, - (P.exists_root_eq_smul_of_mem_weylGroup hy i).choose_spec, mul_smul] - -@[simp] -lemma weylGroupToPerm_apply_reflection : - P.weylGroupToPerm ⟨P.reflection i, P.reflection_mem_weylGroup i⟩ = P.reflection_perm i := by - ext j - apply P.root.injective - rw [weylGroupToPerm, MonoidHom.coe_mk, OneHom.coe_mk, Equiv.coe_fn_mk, root_reflection_perm, - (P.exists_root_eq_smul_of_mem_weylGroup (P.reflection_mem_weylGroup i) j).choose_spec, - LinearEquiv.smul_def] - -@[simp] -lemma range_weylGroupToPerm : - P.weylGroupToPerm.range = Subgroup.closure (range P.reflection_perm) := by - refine (Subgroup.closure_eq_of_le _ ?_ ?_).symm - · rintro - ⟨i, rfl⟩ - simpa only [← weylGroupToPerm_apply_reflection] using mem_range_self _ - · rintro - ⟨⟨w, hw⟩, rfl⟩ - induction hw using Subgroup.closure_induction'' with - | one => - change P.weylGroupToPerm 1 ∈ _ - simpa only [map_one] using Subgroup.one_mem _ - | mem w' hw' => - obtain ⟨i, rfl⟩ := hw' - simpa only [weylGroupToPerm_apply_reflection] using Subgroup.subset_closure (mem_range_self i) - | inv_mem w' hw' => - obtain ⟨i, rfl⟩ := hw' - simpa only [reflection_inv, weylGroupToPerm_apply_reflection] using - Subgroup.subset_closure (mem_range_self i) - | mul w₁ w₂ hw₁ hw₂ h₁ h₂ => - simpa only [← Submonoid.mk_mul_mk _ w₁ w₂ hw₁ hw₂, map_mul] using Subgroup.mul_mem _ h₁ h₂ - lemma pairing_smul_root_eq (k : ι) (hij : P.reflection_perm i = P.reflection_perm j) : P.pairing k i • P.root i = P.pairing k j • P.root j := by have h : P.reflection i (P.root k) = P.reflection j (P.root k) := by @@ -531,12 +491,21 @@ def coxeterWeight : R := pairing P i j * pairing P j i lemma coxeterWeight_swap : coxeterWeight P i j = coxeterWeight P j i := by simp only [coxeterWeight, mul_comm] +lemma exists_int_eq_coxeterWeight [P.IsCrystallographic] (i j : ι) : + ∃ z : ℤ, P.coxeterWeight i j = z := by + obtain ⟨a, ha⟩ := P.exists_int i j + obtain ⟨b, hb⟩ := P.exists_int j i + exact ⟨a * b, by simp [coxeterWeight, ha, hb]⟩ + /-- Two roots are orthogonal when they are fixed by each others' reflections. -/ def IsOrthogonal : Prop := pairing P i j = 0 ∧ pairing P j i = 0 -lemma IsOrthogonal.symm : IsOrthogonal P i j ↔ IsOrthogonal P j i := by +lemma isOrthogonal_symm : IsOrthogonal P i j ↔ IsOrthogonal P j i := by simp only [IsOrthogonal, and_comm] +lemma IsOrthogonal.symm (h : IsOrthogonal P i j) : IsOrthogonal P j i := + ⟨h.2, h.1⟩ + lemma isOrthogonal_comm (h : IsOrthogonal P i j) : Commute (P.reflection i) (P.reflection j) := by rw [commute_iff_eq] ext v diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean index 1f7676b71d4ad..0a28708c322c3 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/CanonicalBilinear.lean @@ -3,9 +3,8 @@ Copyright (c) 2024 Scott Carnahan. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Carnahan -/ -import Mathlib.Algebra.Order.BigOperators.Ring.Finset import Mathlib.Algebra.Ring.SumsOfSquares -import Mathlib.LinearAlgebra.RootSystem.Defs +import Mathlib.LinearAlgebra.RootSystem.RootPositive /-! # The canonical bilinear form on a finite root pairing @@ -55,7 +54,11 @@ namespace RootPairing section CommRing variable [Fintype ι] [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] -(P : RootPairing ι R M N) + (P : RootPairing ι R M N) + +instance : Module.Finite R P.rootSpan := Finite.span_of_finite R <| finite_range P.root + +instance : Module.Finite R P.corootSpan := Finite.span_of_finite R <| finite_range P.coroot /-- An invariant linear map from weight space to coweight space. -/ def Polarization : M →ₗ[R] N := @@ -87,9 +90,50 @@ def CorootForm : LinearMap.BilinForm R N := ∑ i, (P.root' i).smulRight (P.root' i) lemma rootForm_apply_apply (x y : M) : P.RootForm x y = - ∑ (i : ι), P.coroot' i x * P.coroot' i y := by + ∑ i, P.coroot' i x * P.coroot' i y := by + simp [RootForm] + +lemma corootForm_apply_apply (x y : N) : P.CorootForm x y = + ∑ i, P.root' i x * P.root' i y := by + simp [CorootForm] + +lemma toPerfectPairing_apply_apply_Polarization (x y : M) : + P.toPerfectPairing y (P.Polarization x) = P.RootForm x y := by simp [RootForm] +lemma toPerfectPairing_apply_CoPolarization (x : N) : + P.toPerfectPairing (P.CoPolarization x) = P.CorootForm x := by + ext y + exact P.flip.toPerfectPairing_apply_apply_Polarization x y + +lemma flip_comp_polarization_eq_rootForm : + P.flip.toLin ∘ₗ P.Polarization = P.RootForm := by + ext; simp [rootForm_apply_apply, RootPairing.flip] + +lemma self_comp_coPolarization_eq_corootForm : + P.toLin ∘ₗ P.CoPolarization = P.CorootForm := by + ext; simp [corootForm_apply_apply] + +lemma polarization_apply_eq_zero_iff (m : M) : + P.Polarization m = 0 ↔ P.RootForm m = 0 := by + rw [← flip_comp_polarization_eq_rootForm] + refine ⟨fun h ↦ by simp [h], fun h ↦ ?_⟩ + change P.toDualRight (P.Polarization m) = 0 at h + simp only [EmbeddingLike.map_eq_zero_iff] at h + exact h + +lemma coPolarization_apply_eq_zero_iff (n : N) : + P.CoPolarization n = 0 ↔ P.CorootForm n = 0 := + P.flip.polarization_apply_eq_zero_iff n + +lemma ker_polarization_eq_ker_rootForm : + LinearMap.ker P.Polarization = LinearMap.ker P.RootForm := by + ext; simp only [LinearMap.mem_ker, P.polarization_apply_eq_zero_iff] + +lemma ker_copolarization_eq_ker_corootForm : + LinearMap.ker P.CoPolarization = LinearMap.ker P.CorootForm := + P.flip.ker_polarization_eq_ker_rootForm + lemma rootForm_symmetric : LinearMap.IsSymm P.RootForm := by simp [LinearMap.IsSymm, mul_comm, rootForm_apply_apply] @@ -122,6 +166,23 @@ lemma rootForm_self_smul_coroot (i : ι) : rw [Finset.sum_smul, add_neg_eq_zero.mpr rfl] exact sub_eq_zero_of_eq rfl +lemma four_smul_rootForm_sq_eq_coxeterWeight_smul (i j : ι) : + 4 • (P.RootForm (P.root i) (P.root j)) ^ 2 = P.coxeterWeight i j • + (P.RootForm (P.root i) (P.root i) * P.RootForm (P.root j) (P.root j)) := by + have hij : 4 • (P.RootForm (P.root i)) (P.root j) = + 2 • P.toPerfectPairing (P.root j) (2 • P.Polarization (P.root i)) := by + rw [← toPerfectPairing_apply_apply_Polarization, LinearMap.map_smul_of_tower, ← smul_assoc, + Nat.nsmul_eq_mul] + have hji : 2 • (P.RootForm (P.root i)) (P.root j) = + P.toPerfectPairing (P.root i) (2 • P.Polarization (P.root j)) := by + rw [show (P.RootForm (P.root i)) (P.root j) = (P.RootForm (P.root j)) (P.root i) by + apply rootForm_symmetric, ← toPerfectPairing_apply_apply_Polarization, + LinearMap.map_smul_of_tower] + rw [sq, nsmul_eq_mul, ← mul_assoc, ← nsmul_eq_mul, hij, ← rootForm_self_smul_coroot, + smul_mul_assoc 2, ← mul_smul_comm, hji, ← rootForm_self_smul_coroot, map_smul, ← pairing, + map_smul, ← pairing, smul_eq_mul, smul_eq_mul, smul_eq_mul, coxeterWeight] + ring + lemma corootForm_self_smul_root (i : ι) : (P.CorootForm (P.coroot i) (P.coroot i)) • P.root i = 2 • P.CoPolarization (P.coroot i) := rootForm_self_smul_coroot (P.flip) i @@ -143,34 +204,17 @@ theorem range_polarization_domRestrict_le_span_coroot : use fun i => (P.toPerfectPairing x) (P.coroot i) simp -end CommRing +theorem corootSpan_dualAnnihilator_le_ker_rootForm : + P.corootSpan.dualAnnihilator.map P.toDualLeft.symm ≤ LinearMap.ker P.RootForm := by + rw [← SetLike.coe_subset_coe, coe_corootSpan_dualAnnihilator_map] + intro x hx + simp only [coroot', PerfectPairing.flip_apply_apply, mem_setOf_eq] at hx + ext y + simp [rootForm_apply_apply, hx] -section LinearOrderedCommRing - -variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] - [Module R N] (P : RootPairing ι R M N) - -theorem rootForm_self_non_neg (x : M) : 0 ≤ P.RootForm x x := - IsSumSq.nonneg (P.rootForm_self_sum_of_squares x) - -theorem rootForm_self_zero_iff (x : M) : - P.RootForm x x = 0 ↔ ∀ i, P.coroot' i x = 0 := by - simp only [rootForm_apply_apply, PerfectPairing.toLin_apply, LinearMap.coe_comp, comp_apply, - Polarization_apply, map_sum, map_smul, smul_eq_mul] - convert Finset.sum_mul_self_eq_zero_iff Finset.univ fun i => P.coroot' i x - simp - -lemma rootForm_root_self_pos (j : ι) : - 0 < P.RootForm (P.root j) (P.root j) := by - simp only [LinearMap.coe_mk, AddHom.coe_mk, LinearMap.coe_comp, comp_apply, - rootForm_apply_apply, toLin_toPerfectPairing] - refine Finset.sum_pos' (fun i _ => (sq (P.pairing j i)) ▸ sq_nonneg (P.pairing j i)) ?_ - use j - simp - -lemma prod_rootForm_root_self_pos : - 0 < ∏ i, P.RootForm (P.root i) (P.root i) := - Finset.prod_pos fun i _ => rootForm_root_self_pos P i +theorem rootSpan_dualAnnihilator_le_ker_rootForm : + P.rootSpan.dualAnnihilator.map P.toDualRight.symm ≤ LinearMap.ker P.CorootForm := + P.flip.corootSpan_dualAnnihilator_le_ker_rootForm lemma prod_rootForm_smul_coroot_mem_range_domRestrict (i : ι) : (∏ a : ι, P.RootForm (P.root a) (P.root a)) • P.coroot i ∈ @@ -182,6 +226,57 @@ lemma prod_rootForm_smul_coroot_mem_range_domRestrict (i : ι) : use ⟨(c • 2 • P.root i), by aesop⟩ simp +end CommRing + +section LinearOrderedCommRing + +variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] + [Module R N] (P : RootPairing ι R M N) + +theorem rootForm_self_non_neg (x : M) : 0 ≤ P.RootForm x x := + IsSumSq.nonneg (P.rootForm_self_sum_of_squares x) + +lemma rootForm_self_eq_zero_iff {x : M} : + P.RootForm x x = 0 ↔ x ∈ LinearMap.ker P.RootForm := + P.RootForm.apply_apply_same_eq_zero_iff P.rootForm_self_non_neg P.rootForm_symmetric + +lemma rootForm_root_self_pos (i : ι) : + 0 < P.RootForm (P.root i) (P.root i) := by + simp only [rootForm_apply_apply] + exact Finset.sum_pos' (fun j _ ↦ mul_self_nonneg _) ⟨i, by simp⟩ + +/-- SGA3 XXI Prop. 2.3.1 -/ +lemma coxeterWeight_le_four (i j : ι) : P.coxeterWeight i j ≤ 4 := by + set li := P.RootForm (P.root i) (P.root i) + set lj := P.RootForm (P.root j) (P.root j) + set lij := P.RootForm (P.root i) (P.root j) + have hi := P.rootForm_root_self_pos i + have hj := P.rootForm_root_self_pos j + have cs : 4 * lij ^ 2 ≤ 4 * (li * lj) := by + rw [mul_le_mul_left four_pos] + exact LinearMap.BilinForm.apply_sq_le_of_symm P.RootForm P.rootForm_self_non_neg + P.rootForm_symmetric (P.root i) (P.root j) + have key : 4 • lij ^ 2 = _ • (li * lj) := P.four_smul_rootForm_sq_eq_coxeterWeight_smul i j + simp only [nsmul_eq_mul, smul_eq_mul, Nat.cast_ofNat] at key + rwa [key, mul_le_mul_right (by positivity)] at cs + +instance instIsRootPositiveRootForm : IsRootPositive P P.RootForm where + zero_lt_apply_root i := P.rootForm_root_self_pos i + symm := P.rootForm_symmetric + apply_reflection_eq := P.rootForm_reflection_reflection_apply + +lemma coxeterWeight_mem_set_of_isCrystallographic (i j : ι) [P.IsCrystallographic] : + P.coxeterWeight i j ∈ ({0, 1, 2, 3, 4} : Set R) := by + obtain ⟨n, hcn⟩ : ∃ n : ℕ, P.coxeterWeight i j = n := by + obtain ⟨z, hz⟩ := P.exists_int_eq_coxeterWeight i j + have hz₀ : 0 ≤ z := by simpa [hz] using P.coxeterWeight_non_neg P.RootForm i j + obtain ⟨n, rfl⟩ := Int.eq_ofNat_of_zero_le hz₀ + exact ⟨n, by simp [hz]⟩ + have : P.coxeterWeight i j ≤ 4 := P.coxeterWeight_le_four i j + simp only [hcn, mem_insert_iff, mem_singleton_iff] at this ⊢ + norm_cast at this ⊢ + omega + end LinearOrderedCommRing end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean index 1efe86c29f24f..82b70c781f91a 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Finite/Nondegenerate.lean @@ -4,10 +4,10 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Carnahan -/ import Mathlib.LinearAlgebra.BilinearForm.Basic +import Mathlib.LinearAlgebra.BilinearForm.Orthogonal import Mathlib.LinearAlgebra.Dimension.Localization import Mathlib.LinearAlgebra.QuadraticForm.Basic import Mathlib.LinearAlgebra.RootSystem.Finite.CanonicalBilinear -import Mathlib.LinearAlgebra.RootSystem.RootPositive /-! # Nondegeneracy of the polarization on a finite root pairing @@ -23,13 +23,16 @@ Another application is to the faithfulness of the Weyl group action on roots, an Weyl group. ## Main results: - * `RootPairing.rootForm_rootPositive`: `RootForm` is root-positive. - * `RootPairing.polarization_domRestrict_injective`: The polarization restricted to the span of - roots is injective. + * `RootPairing.IsAnisotropic`: We say a finite root pairing is anisotropic if there are no roots / + coroots which have length zero wrt the root / coroot forms. * `RootPairing.rootForm_pos_of_nonzero`: `RootForm` is strictly positive on non-zero linear combinations of roots. This gives us a convenient way to eliminate certain Dynkin diagrams from the classification, since it suffices to produce a nonzero linear combination of simple roots with non-positive norm. + * `RootPairing.rootForm_restrict_nondegenerate_of_ordered`: The root form is non-degenerate if + the coefficients are ordered. + * `RootPairing.rootForm_restrict_nondegenerate_of_isAnisotropic`: the root form is + non-degenerate if the coefficients are a field and the pairing is crystallographic. ## References: * [N. Bourbaki, *Lie groups and {L}ie algebras. {C}hapters 4--6*][bourbaki1968] @@ -50,19 +53,50 @@ open Submodule (span) namespace RootPairing -variable {ι R M N : Type*} +variable {ι R M N : Type*} [Fintype ι] [AddCommGroup M] [AddCommGroup N] -variable [Fintype ι] [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] -[Module R N] (P : RootPairing ι R M N) +section CommRing -lemma rootForm_rootPositive : IsRootPositive P P.RootForm where - zero_lt_apply_root i := P.rootForm_root_self_pos i - symm := P.rootForm_symmetric - apply_reflection_eq := P.rootForm_reflection_reflection_apply +variable [CommRing R] [Module R M] [Module R N] (P : RootPairing ι R M N) -instance : Module.Finite R P.rootSpan := Finite.span_of_finite R <| finite_range P.root +/-- We say a finite root pairing is anisotropic if there are no roots / coroots which have length +zero wrt the root / coroot forms. -instance : Module.Finite R P.corootSpan := Finite.span_of_finite R <| finite_range P.coroot +Examples include crystallographic pairings in characteristic zero +`RootPairing.instIsAnisotropicOfIsCrystallographic` and pairings over ordered scalars. +`RootPairing.instIsAnisotropicOfLinearOrderedCommRing`. -/ +class IsAnisotropic : Prop where + rootForm_root_ne_zero (i : ι) : P.RootForm (P.root i) (P.root i) ≠ 0 + corootForm_coroot_ne_zero (i : ι) : P.CorootForm (P.coroot i) (P.coroot i) ≠ 0 + +instance [P.IsAnisotropic] : P.flip.IsAnisotropic where + rootForm_root_ne_zero := IsAnisotropic.corootForm_coroot_ne_zero + corootForm_coroot_ne_zero := IsAnisotropic.rootForm_root_ne_zero + +/-- An auxiliary lemma en route to `RootPairing.instIsAnisotropicOfIsCrystallographic`. -/ +private lemma rootForm_root_ne_zero_aux [CharZero R] [P.IsCrystallographic] (i : ι) : + P.RootForm (P.root i) (P.root i) ≠ 0 := by + choose z hz using P.exists_int i + simp only [rootForm_apply_apply, PerfectPairing.flip_apply_apply, root_coroot_eq_pairing, ← hz] + suffices 0 < ∑ i, z i * z i by norm_cast; exact this.ne' + refine Finset.sum_pos' (fun i _ ↦ mul_self_nonneg (z i)) ⟨i, Finset.mem_univ i, ?_⟩ + have hzi : z i = 2 := by + specialize hz i + rw [pairing_same] at hz + norm_cast at hz + simp [hzi] + +instance instIsAnisotropicOfIsCrystallographic [CharZero R] [P.IsCrystallographic] : + IsAnisotropic P where + rootForm_root_ne_zero := P.rootForm_root_ne_zero_aux + corootForm_coroot_ne_zero := P.flip.rootForm_root_ne_zero_aux + +end CommRing + +section IsDomain + +variable [CommRing R] [IsDomain R] [Module R M] [Module R N] (P : RootPairing ι R M N) + [P.IsAnisotropic] @[simp] lemma finrank_rootSpan_map_polarization_eq_finrank_corootSpan : @@ -70,9 +104,11 @@ lemma finrank_rootSpan_map_polarization_eq_finrank_corootSpan : rw [← LinearMap.range_domRestrict] apply (Submodule.finrank_mono P.range_polarization_domRestrict_le_span_coroot).antisymm have : IsReflexive R N := PerfectPairing.reflexive_right P.toPerfectPairing + have h_ne : ∏ i, P.RootForm (P.root i) (P.root i) ≠ 0 := + Finset.prod_ne_zero_iff.mpr fun i _ ↦ IsAnisotropic.rootForm_root_ne_zero i refine LinearMap.finrank_le_of_isSMulRegular P.corootSpan (LinearMap.range (P.Polarization.domRestrict P.rootSpan)) - (smul_right_injective N (Ne.symm (ne_of_lt P.prod_rootForm_root_self_pos))) + (smul_right_injective N h_ne) fun _ hx => ?_ obtain ⟨c, hc⟩ := (mem_span_range_iff_exists_fun R).mp hx rw [← hc, Finset.smul_sum] @@ -90,39 +126,97 @@ lemma finrank_corootSpan_eq : finrank R P.corootSpan = finrank R P.rootSpan := le_antisymm P.finrank_corootSpan_le P.flip.finrank_corootSpan_le -lemma disjoint_rootSpan_ker_polarization : - Disjoint P.rootSpan (LinearMap.ker P.Polarization) := by +lemma disjoint_rootSpan_ker_rootForm : + Disjoint P.rootSpan (LinearMap.ker P.RootForm) := by have : IsReflexive R M := PerfectPairing.reflexive_left P.toPerfectPairing - refine Submodule.disjoint_ker_of_finrank_eq (L := P.rootSpan) P.Polarization ?_ - rw [finrank_rootSpan_map_polarization_eq_finrank_corootSpan, finrank_corootSpan_eq] + rw [← P.ker_polarization_eq_ker_rootForm] + refine Submodule.disjoint_ker_of_finrank_le (L := P.rootSpan) P.Polarization ?_ + rw [P.finrank_rootSpan_map_polarization_eq_finrank_corootSpan, P.finrank_corootSpan_eq] + +lemma disjoint_corootSpan_ker_corootForm : + Disjoint P.corootSpan (LinearMap.ker P.CorootForm) := + P.flip.disjoint_rootSpan_ker_rootForm + +end IsDomain + +section Field + +variable [Field R] [Module R M] [Module R N] (P : RootPairing ι R M N) [P.IsAnisotropic] + +lemma isCompl_rootSpan_ker_rootForm : + IsCompl P.rootSpan (LinearMap.ker P.RootForm) := by + have _iM : IsReflexive R M := PerfectPairing.reflexive_left P.toPerfectPairing + have _iN : IsReflexive R N := PerfectPairing.reflexive_right P.toPerfectPairing + refine (Submodule.isCompl_iff_disjoint _ _ ?_).mpr P.disjoint_rootSpan_ker_rootForm + have aux : finrank R M = finrank R P.rootSpan + finrank R P.corootSpan.dualAnnihilator := by + rw [P.toPerfectPairing.finrank_eq, ← P.finrank_corootSpan_eq, + Subspace.finrank_add_finrank_dualAnnihilator_eq P.corootSpan] + rw [aux, add_le_add_iff_left] + convert Submodule.finrank_mono P.corootSpan_dualAnnihilator_le_ker_rootForm + exact (LinearEquiv.finrank_map_eq _ _).symm + +lemma isCompl_corootSpan_ker_corootForm : + IsCompl P.corootSpan (LinearMap.ker P.CorootForm) := + P.flip.isCompl_rootSpan_ker_rootForm + +/-- See also `RootPairing.rootForm_restrict_nondegenerate_of_ordered`. + +Note that this applies to crystallographic root systems in characteristic zero via +`RootPairing.instIsAnisotropicOfIsCrystallographic`. -/ +lemma rootForm_restrict_nondegenerate_of_isAnisotropic : + LinearMap.Nondegenerate (P.RootForm.restrict P.rootSpan) := + P.rootForm_symmetric.nondegenerate_restrict_of_isCompl_ker P.isCompl_rootSpan_ker_rootForm + +@[simp] +lemma orthogonal_rootSpan_eq : + P.RootForm.orthogonal P.rootSpan = LinearMap.ker P.RootForm := by + rw [← LinearMap.BilinForm.orthogonal_top_eq_ker P.rootForm_symmetric.isRefl] + refine le_antisymm ?_ (by intro; aesop) + rintro x hx y - + simp only [LinearMap.BilinForm.mem_orthogonal_iff, LinearMap.BilinForm.IsOrtho] at hx ⊢ + obtain ⟨u, hu, v, hv, rfl⟩ : ∃ᵉ (u ∈ P.rootSpan) (v ∈ LinearMap.ker P.RootForm), u + v = y := by + rw [← Submodule.mem_sup, P.isCompl_rootSpan_ker_rootForm.sup_eq_top]; exact Submodule.mem_top + simp only [LinearMap.mem_ker] at hv + simp [hx _ hu, hv] + +@[simp] +lemma orthogonal_corootSpan_eq : + P.CorootForm.orthogonal P.corootSpan = LinearMap.ker P.CorootForm := + P.flip.orthogonal_rootSpan_eq + +end Field -lemma mem_ker_polarization_of_rootForm_self_eq_zero {x : M} (hx : P.RootForm x x = 0) : - x ∈ LinearMap.ker P.Polarization := by - rw [LinearMap.mem_ker, Polarization_apply] - rw [rootForm_self_zero_iff] at hx - exact Fintype.sum_eq_zero _ fun i ↦ by simp [hx i] +section LinearOrderedCommRing + +variable [LinearOrderedCommRing R] [Module R M] [Module R N] (P : RootPairing ι R M N) + +instance instIsAnisotropicOfLinearOrderedCommRing : IsAnisotropic P where + rootForm_root_ne_zero i := (P.rootForm_root_self_pos i).ne' + corootForm_coroot_ne_zero i := (P.flip.rootForm_root_self_pos i).ne' + +/-- See also `RootPairing.rootForm_restrict_nondegenerate_of_isAnisotropic`. -/ +lemma rootForm_restrict_nondegenerate_of_ordered : + LinearMap.Nondegenerate (P.RootForm.restrict P.rootSpan) := + (P.RootForm.nondegenerate_restrict_iff_disjoint_ker (rootForm_self_non_neg P) + P.rootForm_symmetric).mpr P.disjoint_rootSpan_ker_rootForm lemma eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero {x : M} (hx : x ∈ P.rootSpan) (hx' : P.RootForm x x = 0) : x = 0 := by - rw [← Submodule.mem_bot (R := R), ← P.disjoint_rootSpan_ker_polarization.eq_bot] - exact ⟨hx, P.mem_ker_polarization_of_rootForm_self_eq_zero hx'⟩ + have : x ∈ P.rootSpan ⊓ LinearMap.ker P.RootForm := ⟨hx, P.rootForm_self_eq_zero_iff.mp hx'⟩ + simpa [P.disjoint_rootSpan_ker_rootForm.eq_bot] using this + +lemma rootForm_pos_of_ne_zero {x : M} (hx : x ∈ P.rootSpan) (h : x ≠ 0) : + 0 < P.RootForm x x := by + apply (P.rootForm_self_non_neg x).lt_of_ne + contrapose! h + exact P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero hx h.symm lemma _root_.RootSystem.rootForm_anisotropic (P : RootSystem ι R M N) : P.RootForm.toQuadraticMap.Anisotropic := fun x ↦ P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero <| by simpa only [rootSpan, P.span_eq_top] using Submodule.mem_top -lemma rootForm_pos_of_nonzero {x : M} (hx : x ∈ P.rootSpan) (h : x ≠ 0) : - 0 < P.RootForm x x := by - apply (P.rootForm_self_non_neg x).lt_of_ne - contrapose! h - exact eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero P hx h.symm - -lemma rootForm_restrict_nondegenerate : - (P.RootForm.restrict P.rootSpan).Nondegenerate := - LinearMap.IsRefl.nondegenerate_of_separatingLeft (LinearMap.IsSymm.isRefl fun x y => by - simp [rootForm_apply_apply, mul_comm]) fun x h => SetLike.coe_eq_coe.mp - (P.eq_zero_of_mem_rootSpan_of_rootForm_self_eq_zero (Submodule.coe_mem x) (h x)) +end LinearOrderedCommRing end RootPairing diff --git a/Mathlib/LinearAlgebra/RootSystem/Hom.lean b/Mathlib/LinearAlgebra/RootSystem/Hom.lean index 08f552e72ccc3..1a8565d1abfea 100644 --- a/Mathlib/LinearAlgebra/RootSystem/Hom.lean +++ b/Mathlib/LinearAlgebra/RootSystem/Hom.lean @@ -235,6 +235,12 @@ lemma coweightHom_injective (P : RootPairing ι R M N) : Injective (coweightHom rw [Equiv.symm_apply_apply] at this rw [this, Equiv.apply_symm_apply] +/-- The permutation representation of the endomorphism monoid on the root index set -/ +def indexHom (P : RootPairing ι R M N) : End P →* (ι ≃ ι) where + toFun f := Hom.indexEquiv f + map_one' := by ext; simp + map_mul' x y := by ext; simp + end Hom variable {ι₂ M₂ N₂ : Type*} @@ -349,7 +355,7 @@ lemma comp_assoc {ι₁ M₁ N₁ ι₂ M₂ N₂ ι₃ M₃ N₃ : Type*} [AddC comp (comp h g) f = comp h (comp g f) := by ext <;> simp -/-- The endomorphism monoid of a root pairing. -/ +/-- Equivalences form a monoid. -/ instance (P : RootPairing ι R M N) : Monoid (RootPairing.Equiv P P) where mul := comp mul_assoc := comp_assoc @@ -454,7 +460,7 @@ lemma inv_indexEquiv {ι₂ M₂ N₂ : Type*} [AddCommGroup M₂] [Module R M (f : RootPairing.Equiv P Q) : (symm P Q f).indexEquiv = (Hom.indexEquiv f.toHom).symm := rfl -/-- The endomorphism monoid of a root pairing. -/ +/-- Equivalences form a group. -/ instance (P : RootPairing ι R M N) : Group (RootPairing.Equiv P P) where mul := comp mul_assoc := comp_assoc @@ -528,21 +534,26 @@ def weightHom (P : RootPairing ι R M N) : Aut P →* (M ≃ₗ[R] M) where map_mul' x y := by ext; simp lemma weightHom_toLinearMap {P : RootPairing ι R M N} (g : Aut P) : - ((weightHom P) g).toLinearMap = (Hom.weightHom P) g.toHom := + (weightHom P g).toLinearMap = Hom.weightHom P g.toHom := rfl lemma weightHom_injective (P : RootPairing ι R M N) : Injective (Equiv.weightHom P) := by refine Injective.of_comp (f := LinearEquiv.toLinearMap) fun g g' hgg' => ?_ - let h : ((weightHom P) g).toLinearMap = ((weightHom P) g').toLinearMap := hgg' --`have` gets lint + let h : (weightHom P g).toLinearMap = (weightHom P g').toLinearMap := hgg' --`have` gets lint rw [weightHom_toLinearMap, weightHom_toLinearMap] at h suffices h' : g.toHom = g'.toHom by exact Equiv.ext hgg' (congrArg Hom.coweightMap h') (congrArg Hom.indexEquiv h') exact Hom.weightHom_injective P hgg' +@[simp] +lemma weightEquiv_inv {P : RootPairing ι R M N} (g : Aut P) : + weightEquiv P P g⁻¹ = (weightEquiv P P g)⁻¹ := + LinearEquiv.toLinearMap_inj.mp rfl + /-- The coweight space representation of automorphisms -/ @[simps] def coweightHom (P : RootPairing ι R M N) : Aut P →* (N ≃ₗ[R] N)ᵐᵒᵖ where - toFun g := MulOpposite.op ((coweightEquiv P P) g) + toFun g := MulOpposite.op (coweightEquiv P P g) map_one' := by simp only [MulOpposite.op_eq_one_iff] exact LinearEquiv.toLinearMap_inj.mp rfl @@ -551,14 +562,14 @@ def coweightHom (P : RootPairing ι R M N) : Aut P →* (N ≃ₗ[R] N)ᵐᵒᵖ exact fun x y ↦ rfl lemma coweightHom_toLinearMap {P : RootPairing ι R M N} (g : Aut P) : - (MulOpposite.unop ((coweightHom P) g)).toLinearMap = - MulOpposite.unop ((Hom.coweightHom P) g.toHom) := + (MulOpposite.unop (coweightHom P g)).toLinearMap = + MulOpposite.unop (Hom.coweightHom P g.toHom) := rfl lemma coweightHom_injective (P : RootPairing ι R M N) : Injective (Equiv.coweightHom P) := by refine Injective.of_comp (f := fun a => MulOpposite.op a) fun g g' hgg' => ?_ - have h : (MulOpposite.unop ((coweightHom P) g)).toLinearMap = - (MulOpposite.unop ((coweightHom P) g')).toLinearMap := by + have h : (MulOpposite.unop (coweightHom P g)).toLinearMap = + (MulOpposite.unop (coweightHom P g')).toLinearMap := by simp_all rw [coweightHom_toLinearMap, coweightHom_toLinearMap] at h suffices h' : g.toHom = g'.toHom by @@ -566,6 +577,27 @@ lemma coweightHom_injective (P : RootPairing ι R M N) : Injective (Equiv.coweig apply Hom.coweightHom_injective P exact MulOpposite.unop_inj.mp h +lemma coweightHom_op {P : RootPairing ι R M N} (g : Aut P) : + MulOpposite.unop (coweightHom P g) = coweightEquiv P P g := + rfl + +@[simp] +lemma coweightEquiv_inv {P : RootPairing ι R M N} (g : Aut P) : + coweightEquiv P P g⁻¹ = (coweightEquiv P P g)⁻¹ := + LinearEquiv.toLinearMap_inj.mp rfl + +/-- The permutation representation of the automorphism group on the root index set -/ +@[simps] +def indexHom (P : RootPairing ι R M N) : Aut P →* (ι ≃ ι) where + toFun g := g.toHom.indexEquiv + map_one' := by ext; simp + map_mul' x y := by ext; simp + +@[simp] +lemma indexEquiv_inv {P : RootPairing ι R M N} (g : Aut P) : + (g⁻¹).toHom.indexEquiv = (indexHom P g)⁻¹ := + rfl + /-- The automorphism of a root pairing given by a reflection. -/ def reflection (P : RootPairing ι R M N) (i : ι) : Aut P where weightMap := P.reflection i @@ -601,7 +633,31 @@ lemma reflection_coweightEquiv (P : RootPairing ι R M N) (i : ι) : @[simp] lemma reflection_indexEquiv (P : RootPairing ι R M N) (i : ι) : - (reflection P i).indexEquiv = P.reflection_perm i := rfl + (reflection P i).indexEquiv = P.reflection_perm i := + rfl + +@[simp] +lemma reflection_inv (P : RootPairing ι R M N) (i : ι) : + (reflection P i)⁻¹ = (reflection P i) := by + refine Equiv.ext ?_ ?_ ?_ + · exact LinearMap.ext_iff.mpr (fun x => by simp [← weightEquiv_apply]) + · exact LinearMap.ext_iff.mpr (fun x => by simp [← coweightEquiv_apply]) + · exact _root_.Equiv.ext (fun j => by simp only [← indexHom_apply, map_inv]; simp) + +instance : MulAction P.Aut M where + smul w v := Equiv.weightHom P w v + one_smul _ := rfl + mul_smul _ _ _ := rfl + +instance : MulAction (P.Aut)ᵐᵒᵖ N where + smul w v := (MulOpposite.unop (Equiv.coweightHom P (MulOpposite.unop w))) v + one_smul _ := rfl + mul_smul _ _ _ := rfl + +instance : MulAction P.Aut ι where + smul w i := Equiv.indexHom P w i + one_smul _ := rfl + mul_smul _ _ _ := rfl end Equiv diff --git a/Mathlib/LinearAlgebra/RootSystem/WeylGroup.lean b/Mathlib/LinearAlgebra/RootSystem/WeylGroup.lean new file mode 100644 index 0000000000000..c89c7d4158b1a --- /dev/null +++ b/Mathlib/LinearAlgebra/RootSystem/WeylGroup.lean @@ -0,0 +1,131 @@ +/- +Copyright (c) 2024 Scott Carnahan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Scott Carnahan +-/ +import Mathlib.LinearAlgebra.RootSystem.Hom + +/-! +# The Weyl group of a root pairing +This file defines the Weyl group of a root pairing as the subgroup of automorphisms generated by +reflection automorphisms. This deviates from the existing literature, which typically defines the +Weyl group as the subgroup of linear transformations of the weight space generated by linear +reflections. However, the automorphism group of a root pairing comes with a permutation +representation on the set indexing roots and faithful linear representations on the weight space and +coweight space. Thus, our formalism gives us an isomorphism to the traditional Weyl group together +with the natural dual representation generated by coreflections and the permutation representation +on roots. +## Main definitions + * `RootPairing.weylGroup` : The group of automorphisms generated by reflections. + * `RootPairing.weylGroupToPerm` : The permutation representation of the Weyl group on roots. +## Results + * `RootPairing.range_weylGroup_weightHom` : The image of the weight space representation is equal + to the subgroup generated by linear reflections. + * `RootPairing.range_weylGroup_coweightHom` : The image of the coweight space representation is + equal to the subgroup generated by linear coreflections. + * `RootPairing.range_weylGroupToPerm` : The image of the permutation representation is equal to the + subgroup generated by reflection permutations. +## TODO + * faithfulness of `weylGroupToPerm` when multiplication by 2 is injective on the weight space. +-/ + +open Set Function + +variable {ι R M N : Type*} + +noncomputable section + +namespace RootPairing + +variable [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup N] [Module R N] + (P : RootPairing ι R M N) (i : ι) + +/-- The `Weyl group` of a root pairing is the group of automorphisms of the root pairing generated +by reflections. -/ +def weylGroup : Subgroup (Aut P) := + Subgroup.closure (range (Equiv.reflection P)) + +lemma reflection_mem_weylGroup : Equiv.reflection P i ∈ P.weylGroup := + Subgroup.subset_closure <| mem_range_self i + +lemma range_weylGroup_weightHom : + MonoidHom.range ((Equiv.weightHom P).restrict P.weylGroup) = + Subgroup.closure (range P.reflection) := by + refine (Subgroup.closure_eq_of_le _ ?_ ?_).symm + · rintro - ⟨i, rfl⟩ + simp only [MonoidHom.restrict_range, Subgroup.coe_map, Equiv.weightHom_apply, mem_image, + SetLike.mem_coe] + use Equiv.reflection P i + exact ⟨reflection_mem_weylGroup P i, Equiv.reflection_weightEquiv P i⟩ + · rintro fg ⟨⟨w, hw⟩, rfl⟩ + induction hw using Subgroup.closure_induction'' with + | one => + change ((Equiv.weightHom P).restrict P.weylGroup) 1 ∈ _ + simpa only [map_one] using Subgroup.one_mem _ + | mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [MonoidHom.restrict_apply, Equiv.weightHom_apply, Equiv.reflection_weightEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | inv_mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [Equiv.reflection_inv, MonoidHom.restrict_apply, Equiv.weightHom_apply, + Equiv.reflection_weightEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | mul w₁ w₂ hw₁ hw₂ h₁ h₂ => + simpa only [← Submonoid.mk_mul_mk _ w₁ w₂ hw₁ hw₂, map_mul] using Subgroup.mul_mem _ h₁ h₂ + +lemma range_weylGroup_coweightHom : + MonoidHom.range ((Equiv.coweightHom P).restrict P.weylGroup) = + Subgroup.closure (range (MulOpposite.op ∘ P.coreflection)) := by + refine (Subgroup.closure_eq_of_le _ ?_ ?_).symm + · rintro - ⟨i, rfl⟩ + simp only [MonoidHom.restrict_range, Subgroup.coe_map, Equiv.weightHom_apply, mem_image, + SetLike.mem_coe] + use Equiv.reflection P i + refine ⟨reflection_mem_weylGroup P i, by simp⟩ + · rintro fg ⟨⟨w, hw⟩, rfl⟩ + induction hw using Subgroup.closure_induction'' with + | one => + change ((Equiv.coweightHom P).restrict P.weylGroup) 1 ∈ _ + simpa only [map_one] using Subgroup.one_mem _ + | mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [MonoidHom.restrict_apply, Equiv.coweightHom_apply, Equiv.reflection_coweightEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | inv_mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [Equiv.reflection_inv, MonoidHom.restrict_apply, Equiv.coweightHom_apply, + Equiv.reflection_coweightEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | mul w₁ w₂ hw₁ hw₂ h₁ h₂ => + simpa only [← Submonoid.mk_mul_mk _ w₁ w₂ hw₁ hw₂, map_mul] using Subgroup.mul_mem _ h₁ h₂ + +/-- The permutation representation of the Weyl group induced by `reflection_perm`. -/ +abbrev weylGroupToPerm := (Equiv.indexHom P).restrict P.weylGroup + +lemma range_weylGroupToPerm : + P.weylGroupToPerm.range = Subgroup.closure (range P.reflection_perm) := by + refine (Subgroup.closure_eq_of_le _ ?_ ?_).symm + · rintro - ⟨i, rfl⟩ + simp only [MonoidHom.restrict_range, Subgroup.coe_map, Equiv.weightHom_apply, mem_image, + SetLike.mem_coe] + use Equiv.reflection P i + refine ⟨reflection_mem_weylGroup P i, by simp⟩ + · rintro fg ⟨⟨w, hw⟩, rfl⟩ + induction hw using Subgroup.closure_induction'' with + | one => + change ((Equiv.indexHom P).restrict P.weylGroup) 1 ∈ _ + simpa only [map_one] using Subgroup.one_mem _ + | mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [MonoidHom.restrict_apply, Equiv.indexHom_apply, Equiv.reflection_indexEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | inv_mem w' hw' => + obtain ⟨i, rfl⟩ := hw' + simp only [Equiv.reflection_inv, MonoidHom.restrict_apply, Equiv.indexHom_apply, + Equiv.reflection_indexEquiv] + simpa only [reflection_mem_weylGroup] using Subgroup.subset_closure (mem_range_self i) + | mul w₁ w₂ hw₁ hw₂ h₁ h₂ => + simpa only [← Submonoid.mk_mul_mk _ w₁ w₂ hw₁ hw₂, map_mul] using Subgroup.mul_mem _ h₁ h₂ + +end RootPairing diff --git a/Mathlib/LinearAlgebra/Semisimple.lean b/Mathlib/LinearAlgebra/Semisimple.lean index 34d9925e6aa6a..f96061725cfc2 100644 --- a/Mathlib/LinearAlgebra/Semisimple.lean +++ b/Mathlib/LinearAlgebra/Semisimple.lean @@ -9,6 +9,7 @@ import Mathlib.LinearAlgebra.Basis.VectorSpace import Mathlib.RingTheory.Artinian import Mathlib.RingTheory.Ideal.Quotient.Nilpotent import Mathlib.RingTheory.SimpleModule +import Mathlib.Algebra.Module.Torsion /-! # Semisimple linear endomorphisms @@ -296,7 +297,7 @@ theorem IsSemisimple.of_mem_adjoin_pair {a : End K M} (ha : a ∈ Algebra.adjoin rotate_left 1 · rw [Ideal.span, ← minpoly.ker_aeval_eq_span_minpoly]; exact id · rintro ⟨p⟩; exact p.induction_on (fun k ↦ by simp [R, Algebra.commute_algebraMap_left]) - (fun p q hp hq ↦ by simpa using hp.add_left hq) + (fun p q hp hq ↦ by simpa [R] using hp.add_left hq) fun n k ↦ by simpa [R, pow_succ, ← mul_assoc _ _ X] using (·.mul_left comm) · simpa only [RingHom.mem_ker, eval₂AlgHom'_apply, eval₂_map, AlgHom.comp_algebraMap_of_tower] using minpoly.aeval K g diff --git a/Mathlib/LinearAlgebra/SesquilinearForm.lean b/Mathlib/LinearAlgebra/SesquilinearForm.lean index 99617d933657d..495286b640a80 100644 --- a/Mathlib/LinearAlgebra/SesquilinearForm.lean +++ b/Mathlib/LinearAlgebra/SesquilinearForm.lean @@ -155,6 +155,8 @@ include H theorem eq_zero : ∀ {x y}, B x y = 0 → B y x = 0 := fun {x y} ↦ H x y +theorem eq_iff {x y} : B x y = 0 ↔ B y x = 0 := ⟨H x y, H y x⟩ + theorem ortho_comm {x y} : IsOrtho B x y ↔ IsOrtho B y x := ⟨eq_zero H, eq_zero H⟩ @@ -700,25 +702,54 @@ section CommRing variable [CommRing R] [AddCommGroup M] [Module R M] [AddCommGroup M₁] [Module R M₁] {I I' : R →+* R} -theorem IsRefl.nondegenerate_of_separatingLeft {B : M →ₗ[R] M →ₗ[R] M₁} (hB : B.IsRefl) - (hB' : B.SeparatingLeft) : B.Nondegenerate := by - refine ⟨hB', ?_⟩ +theorem IsRefl.nondegenerate_iff_separatingLeft {B : M →ₗ[R] M →ₗ[R] M₁} (hB : B.IsRefl) : + B.Nondegenerate ↔ B.SeparatingLeft := by + refine ⟨fun h ↦ h.1, fun hB' ↦ ⟨hB', ?_⟩⟩ rw [separatingRight_iff_flip_ker_eq_bot, hB.ker_eq_bot_iff_ker_flip_eq_bot.mp] rwa [← separatingLeft_iff_ker_eq_bot] -theorem IsRefl.nondegenerate_of_separatingRight {B : M →ₗ[R] M →ₗ[R] M₁} (hB : B.IsRefl) - (hB' : B.SeparatingRight) : B.Nondegenerate := by - refine ⟨?_, hB'⟩ +theorem IsRefl.nondegenerate_iff_separatingRight {B : M →ₗ[R] M →ₗ[R] M₁} (hB : B.IsRefl) : + B.Nondegenerate ↔ B.SeparatingRight := by + refine ⟨fun h ↦ h.2, fun hB' ↦ ⟨?_, hB'⟩⟩ rw [separatingLeft_iff_ker_eq_bot, hB.ker_eq_bot_iff_ker_flip_eq_bot.mpr] rwa [← separatingRight_iff_flip_ker_eq_bot] +lemma disjoint_ker_of_nondegenerate_restrict {B : M →ₗ[R] M →ₗ[R] M₁} {W : Submodule R M} + (hW : (B.domRestrict₁₂ W W).Nondegenerate) : + Disjoint W (LinearMap.ker B) := by + refine Submodule.disjoint_def.mpr fun x hx hx' ↦ ?_ + let x' : W := ⟨x, hx⟩ + suffices x' = 0 by simpa [x'] + apply hW.1 x' + simp_rw [Subtype.forall, domRestrict₁₂_apply] + intro y hy + rw [mem_ker] at hx' + simp [hx'] + +lemma IsSymm.nondegenerate_restrict_of_isCompl_ker {B : M →ₗ[R] M →ₗ[R] R} (hB : B.IsSymm) + {W : Submodule R M} (hW : IsCompl W (LinearMap.ker B)) : + (B.domRestrict₁₂ W W).Nondegenerate := by + have hB' : (B.domRestrict₁₂ W W).IsRefl := fun x y ↦ hB.isRefl (W.subtype x) (W.subtype y) + rw [LinearMap.IsRefl.nondegenerate_iff_separatingLeft hB'] + intro ⟨x, hx⟩ hx' + simp only [Submodule.mk_eq_zero] + replace hx' : ∀ y ∈ W, B x y = 0 := by simpa [Subtype.forall] using hx' + replace hx' : x ∈ W ⊓ ker B := by + refine ⟨hx, ?_⟩ + ext y + obtain ⟨u, hu, v, hv, rfl⟩ : ∃ u ∈ W, ∃ v ∈ ker B, u + v = y := by + rw [← Submodule.mem_sup, hW.sup_eq_top]; exact Submodule.mem_top + suffices B x u = 0 by rw [mem_ker] at hv; simpa [← hB.eq v, hv] + exact hx' u hu + simpa [hW.inf_eq_bot] using hx' + /-- The restriction of a reflexive bilinear map `B` onto a submodule `W` is nondegenerate if `W` has trivial intersection with its orthogonal complement, that is `Disjoint W (W.orthogonalBilin B)`. -/ theorem nondegenerate_restrict_of_disjoint_orthogonal {B : M →ₗ[R] M →ₗ[R] M₁} (hB : B.IsRefl) {W : Submodule R M} (hW : Disjoint W (W.orthogonalBilin B)) : (B.domRestrict₁₂ W W).Nondegenerate := by - refine (hB.domRestrict W).nondegenerate_of_separatingLeft ?_ + rw [(hB.domRestrict W).nondegenerate_iff_separatingLeft] rintro ⟨x, hx⟩ b₁ rw [Submodule.mk_eq_zero, ← Submodule.mem_bot R] refine hW.le_bot ⟨hx, fun y hy ↦ ?_⟩ @@ -798,4 +829,133 @@ end CommRing end Nondegenerate +namespace BilinForm + +lemma apply_smul_sub_smul_sub_eq [CommRing R] [AddCommGroup M] [Module R M] + (B : LinearMap.BilinForm R M) (x y : M) : + B ((B x y) • x - (B x x) • y) ((B x y) • x - (B x x) • y) = + (B x x) * ((B x x) * (B y y) - (B x y) * (B y x)) := by + simp only [map_sub, map_smul, sub_apply, smul_apply, smul_eq_mul, mul_sub, + mul_comm (B x y) (B x x), mul_left_comm (B x y) (B x x)] + abel + +variable [LinearOrderedCommRing R] [AddCommGroup M] [Module R M] (B : LinearMap.BilinForm R M) + +/-- The **Cauchy-Schwarz inequality** for positive semidefinite forms. -/ +lemma apply_mul_apply_le_of_forall_zero_le (hs : ∀ x, 0 ≤ B x x) (x y : M) : + (B x y) * (B y x) ≤ (B x x) * (B y y) := by + have aux (x y : M) : 0 ≤ (B x x) * ((B x x) * (B y y) - (B x y) * (B y x)) := by + rw [← apply_smul_sub_smul_sub_eq B x y] + exact hs (B x y • x - B x x • y) + rcases lt_or_le 0 (B x x) with hx | hx + · exact sub_nonneg.mp <| nonneg_of_mul_nonneg_right (aux x y) hx + · replace hx : B x x = 0 := le_antisymm hx (hs x) + rcases lt_or_le 0 (B y y) with hy | hy + · rw [mul_comm (B x y), mul_comm (B x x)] + exact sub_nonneg.mp <| nonneg_of_mul_nonneg_right (aux y x) hy + · replace hy : B y y = 0 := le_antisymm hy (hs y) + suffices B x y = - B y x by simpa [this, hx, hy] using mul_self_nonneg (B y x) + rw [eq_neg_iff_add_eq_zero] + apply le_antisymm + · simpa [hx, hy, le_neg_iff_add_nonpos_left] using hs (x - y) + · simpa [hx, hy] using hs (x + y) + +/-- The **Cauchy-Schwarz inequality** for positive semidefinite symmetric forms. -/ +lemma apply_sq_le_of_symm (hs : ∀ x, 0 ≤ B x x) (hB : B.IsSymm) (x y : M) : + (B x y) ^ 2 ≤ (B x x) * (B y y) := by + rw [show (B x y) ^ 2 = (B x y) * (B y x) by rw [sq, ← hB, RingHom.id_apply]] + exact apply_mul_apply_le_of_forall_zero_le B hs x y + +/-- The equality case of **Cauchy-Schwarz**. -/ +lemma not_linearIndependent_of_apply_mul_apply_eq (hp : ∀ x, x ≠ 0 → 0 < B x x) + (x y : M) (he : (B x y) * (B y x) = (B x x) * (B y y)) : + ¬ LinearIndependent R ![x, y] := by + have hz : (B x y) • x - (B x x) • y = 0 := by + by_contra hc + exact (ne_of_lt (hp ((B x) y • x - (B x) x • y) hc)).symm <| + (apply_smul_sub_smul_sub_eq B x y).symm ▸ (mul_eq_zero_of_right ((B x) x) + (sub_eq_zero_of_eq he.symm)) + by_contra hL + by_cases hx : x = 0 + · simpa [hx] using LinearIndependent.ne_zero 0 hL + · have h := sub_eq_zero.mpr (sub_eq_zero.mp hz).symm + rw [sub_eq_add_neg, ← neg_smul, add_comm] at h + exact (Ne.symm (ne_of_lt (hp x hx))) (LinearIndependent.eq_zero_of_pair hL h).2 + +/-- Strict **Cauchy-Schwarz** is equivalent to linear independence for positive definite forms. -/ +lemma apply_mul_apply_lt_iff_linearIndependent [NoZeroSMulDivisors R M] + (hp : ∀ x, x ≠ 0 → 0 < B x x) (x y : M) : + (B x y) * (B y x) < (B x x) * (B y y) ↔ LinearIndependent R ![x, y] := by + have hle : ∀ z, 0 ≤ B z z := by + intro z + by_cases hz : z = 0; simp [hz] + exact le_of_lt (hp z hz) + constructor + · contrapose! + intro h + rw [LinearIndependent.pair_iff] at h + push_neg at h + obtain ⟨r, s, hl, h0⟩ := h + by_cases hr : r = 0; · simp_all + by_cases hs : s = 0; · simp_all + suffices + (B (r • x) (r • x)) * (B (s • y) (s • y)) = (B (r • x) (s • y)) * (B (s • y) (r • x)) by + simp only [map_smul, smul_apply, smul_eq_mul] at this + rw [show r * (r * (B x) x) * (s * (s * (B y) y)) = (r * r * s * s) * ((B x) x * (B y) y) by + ring, show s * (r * (B x) y) * (r * (s * (B y) x)) = (r * r * s * s) * ((B x) y * (B y) x) + by ring] at this + have hrs : r * r * s * s ≠ 0 := by simp [hr, hs] + exact le_of_eq <| mul_right_injective₀ hrs this + simp [show s • y = - r • x by rwa [neg_smul, ← add_eq_zero_iff_eq_neg']] + · contrapose! + intro h + refine not_linearIndependent_of_apply_mul_apply_eq B hp x y (le_antisymm + (apply_mul_apply_le_of_forall_zero_le B hle x y) h) + +/-- Strict **Cauchy-Schwarz** is equivalent to linear independence for positive definite symmetric +forms. -/ +lemma apply_sq_lt_iff_linearIndependent_of_symm [NoZeroSMulDivisors R M] + (hp : ∀ x, x ≠ 0 → 0 < B x x) (hB: B.IsSymm) (x y : M) : + (B x y) ^ 2 < (B x x) * (B y y) ↔ LinearIndependent R ![x, y] := by + rw [show (B x y) ^ 2 = (B x y) * (B y x) by rw [sq, ← hB, RingHom.id_apply]] + exact apply_mul_apply_lt_iff_linearIndependent B hp x y + +lemma apply_apply_same_eq_zero_iff (hs : ∀ x, 0 ≤ B x x) (hB : B.IsSymm) {x : M} : + B x x = 0 ↔ x ∈ LinearMap.ker B := by + rw [LinearMap.mem_ker] + refine ⟨fun h ↦ ?_, fun h ↦ by simp [h]⟩ + ext y + have := B.apply_sq_le_of_symm hs hB x y + simp only [h, zero_mul] at this + exact pow_eq_zero <| le_antisymm this (sq_nonneg (B x y)) + +lemma nondegenerate_iff (hs : ∀ x, 0 ≤ B x x) (hB : B.IsSymm) : + B.Nondegenerate ↔ ∀ x, B x x = 0 ↔ x = 0 := by + simp_rw [hB.isRefl.nondegenerate_iff_separatingLeft, separatingLeft_iff_ker_eq_bot, + Submodule.eq_bot_iff, B.apply_apply_same_eq_zero_iff hs hB, mem_ker] + exact forall_congr' fun x ↦ by aesop + +/-- A convenience variant of `LinearMap.BilinForm.nondegenerate_iff` characterising nondegeneracy as +positive definiteness. -/ +lemma nondegenerate_iff' (hs : ∀ x, 0 ≤ B x x) (hB : B.IsSymm) : + B.Nondegenerate ↔ ∀ x, x ≠ 0 → 0 < B x x := by + rw [B.nondegenerate_iff hs hB, ← not_iff_not] + push_neg + exact exists_congr fun x ↦ ⟨by aesop, fun ⟨h₀, h⟩ ↦ Or.inl ⟨le_antisymm h (hs x), h₀⟩⟩ + +lemma nondegenerate_restrict_iff_disjoint_ker (hs : ∀ x, 0 ≤ B x x) (hB : B.IsSymm) + {W : Submodule R M} : + (B.domRestrict₁₂ W W).Nondegenerate ↔ Disjoint W (LinearMap.ker B) := by + refine ⟨disjoint_ker_of_nondegenerate_restrict, fun hW ↦ ?_⟩ + have hB' : (B.domRestrict₁₂ W W).IsRefl := fun x y ↦ hB.isRefl (W.subtype x) (W.subtype y) + rw [IsRefl.nondegenerate_iff_separatingLeft hB'] + intro ⟨x, hx⟩ h + simp_rw [Subtype.forall, domRestrict₁₂_apply] at h + specialize h x hx + rw [B.apply_apply_same_eq_zero_iff hs hB] at h + have key : x ∈ W ⊓ LinearMap.ker B := ⟨hx, h⟩ + simpa [hW.eq_bot] using key + +end BilinForm + end LinearMap diff --git a/Mathlib/LinearAlgebra/Span/Basic.lean b/Mathlib/LinearAlgebra/Span/Basic.lean index 0a1c4349e44cc..997c8ed3189d4 100644 --- a/Mathlib/LinearAlgebra/Span/Basic.lean +++ b/Mathlib/LinearAlgebra/Span/Basic.lean @@ -80,6 +80,57 @@ theorem span_preimage_le (f : F) (s : Set M₂) : alias _root_.LinearMap.span_preimage_le := Submodule.span_preimage_le +section + +variable {N : Type*} [AddCommMonoid N] [Module R N] + +lemma linearMap_eq_iff_of_eq_span {V : Submodule R M} (f g : V →ₗ[R] N) + {S : Set M} (hV : V = span R S) : + f = g ↔ ∀ (s : S), f ⟨s, by simpa only [hV] using subset_span (by simp)⟩ = + g ⟨s, by simpa only [hV] using subset_span (by simp)⟩ := by + constructor + · rintro rfl _ + rfl + · intro h + subst hV + suffices ∀ (x : M) (hx : x ∈ span R S), f ⟨x, hx⟩ = g ⟨x, hx⟩ by + ext ⟨x, hx⟩ + exact this x hx + intro x hx + induction hx using span_induction with + | mem x hx => exact h ⟨x, hx⟩ + | zero => erw [map_zero, map_zero] + | add x y hx hy hx' hy' => + erw [f.map_add ⟨x, hx⟩ ⟨y, hy⟩, g.map_add ⟨x, hx⟩ ⟨y, hy⟩] + rw [hx', hy'] + | smul a x hx hx' => + erw [f.map_smul a ⟨x, hx⟩, g.map_smul a ⟨x, hx⟩] + rw [hx'] + +lemma linearMap_eq_iff_of_span_eq_top (f g : M →ₗ[R] N) + {S : Set M} (hM : span R S = ⊤) : + f = g ↔ ∀ (s : S), f s = g s := by + convert linearMap_eq_iff_of_eq_span (f.comp (Submodule.subtype _)) + (g.comp (Submodule.subtype _)) hM.symm + constructor + · rintro rfl + rfl + · intro h + ext x + exact DFunLike.congr_fun h ⟨x, by simp⟩ + +lemma linearMap_eq_zero_iff_of_span_eq_top (f : M →ₗ[R] N) + {S : Set M} (hM : span R S = ⊤) : + f = 0 ↔ ∀ (s : S), f s = 0 := + linearMap_eq_iff_of_span_eq_top f 0 hM + +lemma linearMap_eq_zero_iff_of_eq_span {V : Submodule R M} (f : V →ₗ[R] N) + {S : Set M} (hV : V = span R S) : + f = 0 ↔ ∀ (s : S), f ⟨s, by simpa only [hV] using subset_span (by simp)⟩ = 0 := + linearMap_eq_iff_of_eq_span f 0 hV + +end + /-- See `Submodule.span_smul_eq` (in `RingTheory.Ideal.Operations`) for `span R (r • s) = r • span R s` that holds for arbitrary `r` in a `CommSemiring`. -/ theorem span_smul_eq_of_isUnit (s : Set M) (r : R) (hr : IsUnit r) : span R (r • s) = span R s := by diff --git a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean index 231c9e14ba44f..75d5ed0bc25c0 100644 --- a/Mathlib/LinearAlgebra/TensorProduct/Basic.lean +++ b/Mathlib/LinearAlgebra/TensorProduct/Basic.lean @@ -45,7 +45,7 @@ section Semiring variable {R : Type*} [CommSemiring R] variable {R' : Type*} [Monoid R'] variable {R'' : Type*} [Semiring R''] -variable {M : Type*} {N : Type*} {P : Type*} {Q : Type*} {S : Type*} {T : Type*} +variable {A M N P Q S T : Type*} variable [AddCommMonoid M] [AddCommMonoid N] [AddCommMonoid P] variable [AddCommMonoid Q] [AddCommMonoid S] [AddCommMonoid T] variable [Module R M] [Module R N] [Module R Q] [Module R S] [Module R T] @@ -91,6 +91,9 @@ namespace TensorProduct section Module +protected instance zero : Zero (M ⊗[R] N) := + (addConGen (TensorProduct.Eqv R M N)).zero + protected instance add : Add (M ⊗[R] N) := (addConGen (TensorProduct.Eqv R M N)).hasAdd @@ -99,7 +102,8 @@ instance addZeroClass : AddZeroClass (M ⊗[R] N) := /- The `toAdd` field is given explicitly as `TensorProduct.add` for performance reasons. This avoids any need to unfold `Con.addMonoid` when the type checker is checking that instance diagrams commute -/ - toAdd := TensorProduct.add _ _ } + toAdd := TensorProduct.add _ _ + toZero := TensorProduct.zero _ _ } instance addSemigroup : AddSemigroup (M ⊗[R] N) := { (addConGen (TensorProduct.Eqv R M N)).addMonoid with @@ -320,7 +324,7 @@ protected theorem add_smul (r s : R'') (x : M ⊗[R] N) : (r + s) • x = r • instance addMonoid : AddMonoid (M ⊗[R] N) := { TensorProduct.addZeroClass _ _ with toAddSemigroup := TensorProduct.addSemigroup _ _ - toZero := (TensorProduct.addZeroClass _ _).toZero + toZero := TensorProduct.zero _ _ nsmul := fun n v => n • v nsmul_zero := by simp [TensorProduct.zero_smul] nsmul_succ := by simp only [TensorProduct.one_smul, TensorProduct.add_smul, add_comm, @@ -548,49 +552,6 @@ theorem lift_compr₂ (g : P →ₗ[R] Q) : lift (f.compr₂ g) = g.comp (lift f theorem lift_mk_compr₂ (f : M ⊗ N →ₗ[R] P) : lift ((mk R M N).compr₂ f) = f := by rw [lift_compr₂ f, lift_mk, LinearMap.comp_id] -section ScalarTower - -variable (R M N A) [CommSemiring A] [Module A M] [Module A N] [SMulCommClass R A M] - [CompatibleSMul R A M N] - -/-- If M and N are both R- and A-modules and their actions on them commute, -and if the A-action on `M ⊗[R] N` can switch between the two factors, then there is a -canonical A-linear map from `M ⊗[A] N` to `M ⊗[R] N`. -/ -def mapOfCompatibleSMul : M ⊗[A] N →ₗ[A] M ⊗[R] N := - lift - { toFun := fun m ↦ - { __ := mk R M N m - map_smul' := fun _ _ ↦ (smul_tmul _ _ _).symm } - map_add' := fun _ _ ↦ LinearMap.ext <| by simp - map_smul' := fun _ _ ↦ rfl } - -@[simp] theorem mapOfCompatibleSMul_tmul (m n) : mapOfCompatibleSMul R M N A (m ⊗ₜ n) = m ⊗ₜ n := - rfl - -attribute [local instance] SMulCommClass.symm - -/-- `mapOfCompatibleSMul R M N A` is also A-linear. -/ -def mapOfCompatibleSMul' : M ⊗[A] N →ₗ[R] M ⊗[R] N where - __ := mapOfCompatibleSMul R M N A - map_smul' _ x := x.induction_on (map_zero _) (fun _ _ ↦ by simp [smul_tmul']) - fun _ _ h h' ↦ by simpa using congr($h + $h') - -theorem mapOfCompatibleSMul_surjective : Function.Surjective (mapOfCompatibleSMul R M N A) := - fun x ↦ x.induction_on (⟨0, map_zero _⟩) (fun m n ↦ ⟨_, mapOfCompatibleSMul_tmul ..⟩) - fun _ _ ⟨x, hx⟩ ⟨y, hy⟩ ↦ ⟨x + y, by simpa using congr($hx + $hy)⟩ - -/-- If the R- and A-actions on M and N satisfy `CompatibleSMul` both ways, -then `M ⊗[A] N` is canonically isomorphic to `M ⊗[R] N`. -/ -def equivOfCompatibleSMul [CompatibleSMul A R M N] : M ⊗[A] N ≃ₗ[A] M ⊗[R] N where - __ := mapOfCompatibleSMul R M N A - invFun := mapOfCompatibleSMul A M N R - left_inv x := x.induction_on (map_zero _) (fun _ _ ↦ rfl) - fun _ _ h h' ↦ by simpa using congr($h + $h') - right_inv x := x.induction_on (map_zero _) (fun _ _ ↦ rfl) - fun _ _ h h' ↦ by simpa using congr($h + $h') - -end ScalarTower - /-- This used to be an `@[ext]` lemma, but it fails very slowly when the `ext` tactic tries to apply it in some cases, notably when one wants to show equality of two linear maps. The `@[ext]` attribute is now added locally where it is needed. Using this as the `@[ext]` lemma instead of @@ -752,6 +713,60 @@ variable (R) in theorem lid_eq_rid : TensorProduct.lid R R = TensorProduct.rid R R := LinearEquiv.toLinearMap_injective <| ext' mul_comm +section CompatibleSMul + +variable (R A M N) [CommSemiring A] [Module A M] [Module A N] [SMulCommClass R A M] + [CompatibleSMul R A M N] + +/-- If M and N are both R- and A-modules and their actions on them commute, +and if the A-action on `M ⊗[R] N` can switch between the two factors, then there is a +canonical A-linear map from `M ⊗[A] N` to `M ⊗[R] N`. -/ +def mapOfCompatibleSMul : M ⊗[A] N →ₗ[A] M ⊗[R] N := + lift + { toFun := fun m ↦ + { __ := mk R M N m + map_smul' := fun _ _ ↦ (smul_tmul _ _ _).symm } + map_add' := fun _ _ ↦ LinearMap.ext <| by simp + map_smul' := fun _ _ ↦ rfl } + +@[simp] theorem mapOfCompatibleSMul_tmul (m n) : mapOfCompatibleSMul R A M N (m ⊗ₜ n) = m ⊗ₜ n := + rfl + +theorem mapOfCompatibleSMul_surjective : Function.Surjective (mapOfCompatibleSMul R A M N) := + fun x ↦ x.induction_on (⟨0, map_zero _⟩) (fun m n ↦ ⟨_, mapOfCompatibleSMul_tmul ..⟩) + fun _ _ ⟨x, hx⟩ ⟨y, hy⟩ ↦ ⟨x + y, by simpa using congr($hx + $hy)⟩ + +attribute [local instance] SMulCommClass.symm + +/-- `mapOfCompatibleSMul R A M N` is also R-linear. -/ +def mapOfCompatibleSMul' : M ⊗[A] N →ₗ[R] M ⊗[R] N where + __ := mapOfCompatibleSMul R A M N + map_smul' _ x := x.induction_on (map_zero _) (fun _ _ ↦ by simp [smul_tmul']) + fun _ _ h h' ↦ by simpa using congr($h + $h') + +/-- If the R- and A-actions on M and N satisfy `CompatibleSMul` both ways, +then `M ⊗[A] N` is canonically isomorphic to `M ⊗[R] N`. -/ +def equivOfCompatibleSMul [CompatibleSMul A R M N] : M ⊗[A] N ≃ₗ[A] M ⊗[R] N where + __ := mapOfCompatibleSMul R A M N + invFun := mapOfCompatibleSMul A R M N + left_inv x := x.induction_on (map_zero _) (fun _ _ ↦ rfl) + fun _ _ h h' ↦ by simpa using congr($h + $h') + right_inv x := x.induction_on (map_zero _) (fun _ _ ↦ rfl) + fun _ _ h h' ↦ by simpa using congr($h + $h') + +omit [SMulCommClass R A M] + +variable [Module R A] [SMulCommClass R A A] [CompatibleSMul R A A M] [CompatibleSMul A R A M] + +/-- If the R- and A- action on A and M satisfy `CompatibleSMul` both ways, +then `A ⊗[R] M` is canonically isomorphic to `M`. -/ +def lidOfCompatibleSMul : A ⊗[R] M ≃ₗ[A] M := + (equivOfCompatibleSMul R A A M).symm ≪≫ₗ TensorProduct.lid _ _ + +theorem lidOfCompatibleSMul_tmul (a m) : lidOfCompatibleSMul R A M (a ⊗ₜ[R] m) = a • m := rfl + +end CompatibleSMul + open LinearMap section diff --git a/Mathlib/Logic/Basic.lean b/Mathlib/Logic/Basic.lean index 13c8fd29ba91a..d63de1913084e 100644 --- a/Mathlib/Logic/Basic.lean +++ b/Mathlib/Logic/Basic.lean @@ -353,6 +353,10 @@ theorem xor_iff_iff_not : Xor' a b ↔ (a ↔ ¬b) := by simp only [← @xor_not theorem xor_iff_not_iff' : Xor' a b ↔ (¬a ↔ b) := by simp only [← @xor_not_left _ b, not_not] +theorem xor_iff_or_and_not_and (a b : Prop) : Xor' a b ↔ (a ∨ b) ∧ (¬ (a ∧ b)) := by + rw [Xor', or_and_right, not_and_or, and_or_left, and_not_self_iff, false_or, + and_or_left, and_not_self_iff, or_false] + end Propositional /-! ### Declarations about equality -/ diff --git a/Mathlib/Logic/Encodable/Basic.lean b/Mathlib/Logic/Encodable/Basic.lean index 60412ec201292..e1558f646d24a 100644 --- a/Mathlib/Logic/Encodable/Basic.lean +++ b/Mathlib/Logic/Encodable/Basic.lean @@ -592,7 +592,7 @@ section Quotient open Encodable Quotient -variable {α : Type*} {s : Setoid α} [@DecidableRel α (· ≈ ·)] [Encodable α] +variable {α : Type*} {s : Setoid α} [DecidableRel (α := α) (· ≈ ·)] [Encodable α] /-- Representative of an equivalence class. This is a computable version of `Quot.out` for a setoid on an encodable type. -/ diff --git a/Mathlib/Logic/Equiv/Basic.lean b/Mathlib/Logic/Equiv/Basic.lean index 070edf6a55b4e..0a2b42804e59c 100644 --- a/Mathlib/Logic/Equiv/Basic.lean +++ b/Mathlib/Logic/Equiv/Basic.lean @@ -22,7 +22,7 @@ import Mathlib.Tactic.CC /-! # Equivalence between types -In this file we continue the work on equivalences begun in `Logic/Equiv/Defs.lean`, defining +In this file we continue the work on equivalences begun in `Mathlib/Logic/Equiv/Defs.lean`, defining * canonical isomorphisms between various types: e.g., @@ -38,7 +38,7 @@ In this file we continue the work on equivalences begun in `Logic/Equiv/Defs.lea `eb : β₁ ≃ β₂` using `Prod.map`. More definitions of this kind can be found in other files. - E.g., `Logic/Equiv/TransferInstance.lean` does it for many algebraic type classes like + E.g., `Mathlib/Logic/Equiv/TransferInstance.lean` does it for many algebraic type classes like `Group`, `Module`, etc. ## Tags diff --git a/Mathlib/Logic/Equiv/Defs.lean b/Mathlib/Logic/Equiv/Defs.lean index 9c482264afc23..ceaaf86181c2d 100644 --- a/Mathlib/Logic/Equiv/Defs.lean +++ b/Mathlib/Logic/Equiv/Defs.lean @@ -19,7 +19,7 @@ In this file we define two types: not equality!) to express that various `Type`s or `Sort`s are equivalent. * `Equiv.Perm α`: the group of permutations `α ≃ α`. More lemmas about `Equiv.Perm` can be found in - `GroupTheory.Perm`. + `Mathlib.GroupTheory.Perm`. Then we define @@ -41,10 +41,11 @@ Then we define - `Equiv.unique` takes `e : α ≃ β` and `[Unique β]` and returns `Unique α`; - `Equiv.decidableEq` takes `e : α ≃ β` and `[DecidableEq β]` and returns `DecidableEq α`. - More definitions of this kind can be found in other files. E.g., `Data.Equiv.TransferInstance` - does it for many algebraic type classes like `Group`, `Module`, etc. + More definitions of this kind can be found in other files. + E.g., `Mathlib.Logic.Equiv.TransferInstance` does it for many algebraic type classes like + `Group`, `Module`, etc. -Many more such isomorphisms and operations are defined in `Logic.Equiv.Basic`. +Many more such isomorphisms and operations are defined in `Mathlib.Logic.Equiv.Basic`. ## Tags diff --git a/Mathlib/Logic/Equiv/List.lean b/Mathlib/Logic/Equiv/List.lean index c0753898bf0dc..6a6bb07e4ed21 100644 --- a/Mathlib/Logic/Equiv/List.lean +++ b/Mathlib/Logic/Equiv/List.lean @@ -127,11 +127,11 @@ noncomputable def _root_.Fintype.toEncodable (α : Type*) [Fintype α] : Encodab classical exact (Fintype.truncEncodable α).out /-- If `α` is encodable, then so is `Vector α n`. -/ -instance _root_.Vector.encodable [Encodable α] {n} : Encodable (Vector α n) := +instance Mathlib.Vector.encodable [Encodable α] {n} : Encodable (Mathlib.Vector α n) := Subtype.encodable /-- If `α` is countable, then so is `Vector α n`. -/ -instance _root_.Vector.countable [Countable α] {n} : Countable (Vector α n) := +instance Mathlib.Vector.countable [Countable α] {n} : Countable (Mathlib.Vector α n) := Subtype.countable /-- If `α` is encodable, then so is `Fin n → α`. -/ diff --git a/Mathlib/Logic/Equiv/TransferInstance.lean b/Mathlib/Logic/Equiv/TransferInstance.lean index e1e5ce7366f08..66dfeace0399c 100644 --- a/Mathlib/Logic/Equiv/TransferInstance.lean +++ b/Mathlib/Logic/Equiv/TransferInstance.lean @@ -186,7 +186,7 @@ theorem ringEquiv_symm_apply (e : α ≃ β) [Add β] [Mul β] (b : β) : by variable (α) in /-- Shrink `α` to a smaller universe preserves ring structure. -/ -noncomputable def _root_.Shrink.ringEquiv [Small.{v} α] [Ring α] : Shrink.{v} α ≃+* α := +noncomputable def _root_.Shrink.ringEquiv [Small.{v} α] [Add α] [Mul α] : Shrink.{v} α ≃+* α := (equivShrink α).symm.ringEquiv /-- Transfer `Semigroup` across an `Equiv` -/ @@ -471,10 +471,10 @@ noncomputable instance [Small.{v} α] [Nontrivial α] : Nontrivial (Shrink.{v} (equivShrink α).symm.nontrivial /-- Transfer `IsDomain` across an `Equiv` -/ -protected theorem isDomain [Ring α] [Ring β] [IsDomain β] (e : α ≃+* β) : IsDomain α := +protected theorem isDomain [Semiring α] [Semiring β] [IsDomain β] (e : α ≃+* β) : IsDomain α := Function.Injective.isDomain e.toRingHom e.injective -noncomputable instance [Small.{v} α] [Ring α] [IsDomain α] : IsDomain (Shrink.{v} α) := +noncomputable instance [Small.{v} α] [Semiring α] [IsDomain α] : IsDomain (Shrink.{v} α) := Equiv.isDomain (Shrink.ringEquiv α) /-- Transfer `NNRatCast` across an `Equiv` -/ @@ -621,10 +621,9 @@ protected abbrev algebra (e : α ≃ β) [Semiring β] : simp only [apply_symm_apply, Algebra.mul_smul_comm] lemma algebraMap_def (e : α ≃ β) [Semiring β] [Algebra R β] (r : R) : - let _ := Equiv.semiring e - let _ := Equiv.algebra R e - (algebraMap R α) r = e.symm ((algebraMap R β) r) := by - intros + (@algebraMap R α _ (Equiv.semiring e) (Equiv.algebra R e)) r = e.symm ((algebraMap R β) r) := by + let _ := Equiv.semiring e + let _ := Equiv.algebra R e simp only [Algebra.algebraMap_eq_smul_one] show e.symm (r • e 1) = e.symm (r • 1) simp only [Equiv.one_def, apply_symm_apply] diff --git a/Mathlib/Logic/Function/Basic.lean b/Mathlib/Logic/Function/Basic.lean index 5f794b63872c6..a1af4bbb91992 100644 --- a/Mathlib/Logic/Function/Basic.lean +++ b/Mathlib/Logic/Function/Basic.lean @@ -267,7 +267,7 @@ theorem not_surjective_Type {α : Type u} (f : α → Type max u v) : ¬Surjecti have hg : Injective g := by intro s t h suffices cast hU (g s).2 = cast hU (g t).2 by - simp only [cast_cast, cast_eq] at this + simp only [g, cast_cast, cast_eq] at this assumption · congr exact cantor_injective g hg diff --git a/Mathlib/Logic/IsEmpty.lean b/Mathlib/Logic/IsEmpty.lean index b46a933890f1c..aad5c6c29d0ee 100644 --- a/Mathlib/Logic/IsEmpty.lean +++ b/Mathlib/Logic/IsEmpty.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Floris van Doorn -/ import Mathlib.Logic.Function.Basic +import Mathlib.Logic.Relator /-! # Types that are empty @@ -204,3 +205,19 @@ variable {α} theorem Function.extend_of_isEmpty [IsEmpty α] (f : α → β) (g : α → γ) (h : β → γ) : Function.extend f g h = h := funext fun _ ↦ (Function.extend_apply' _ _ _) fun ⟨a, _⟩ ↦ isEmptyElim a + +open Relator + +variable {α β : Type*} (R : α → β → Prop) + +@[simp] +theorem leftTotal_empty [IsEmpty α] : LeftTotal R := by + simp only [LeftTotal, IsEmpty.forall_iff] + +@[simp] +theorem rightTotal_empty [IsEmpty β] : RightTotal R := by + simp only [RightTotal, IsEmpty.forall_iff] + +@[simp] +theorem biTotal_empty [IsEmpty α] [IsEmpty β] : BiTotal R := + ⟨leftTotal_empty R, rightTotal_empty R⟩ diff --git a/Mathlib/Logic/Small/List.lean b/Mathlib/Logic/Small/List.lean index 13b6fd0b0469a..f0706af610d10 100644 --- a/Mathlib/Logic/Small/List.lean +++ b/Mathlib/Logic/Small/List.lean @@ -18,9 +18,9 @@ universe u v open Mathlib -instance smallVector {α : Type v} {n : ℕ} [Small.{u} α] : Small.{u} (Vector α n) := +instance smallVector {α : Type v} {n : ℕ} [Small.{u} α] : Small.{u} (Mathlib.Vector α n) := small_of_injective (Equiv.vectorEquivFin α n).injective instance smallList {α : Type v} [Small.{u} α] : Small.{u} (List α) := by - let e : (Σn, Vector α n) ≃ List α := Equiv.sigmaFiberEquiv List.length + let e : (Σn, Mathlib.Vector α n) ≃ List α := Equiv.sigmaFiberEquiv List.length exact small_of_surjective e.surjective diff --git a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean index 0d80172e45051..5ed34323264cf 100644 --- a/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean +++ b/Mathlib/MeasureTheory/Constructions/BorelSpace/Real.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Yury Kudryashov -/ import Mathlib.MeasureTheory.Constructions.BorelSpace.Order +import Mathlib.MeasureTheory.MeasurableSpace.Prod /-! # Borel (measurable) spaces ℝ, ℝ≥0, ℝ≥0∞ @@ -465,6 +466,72 @@ _root_.measurable_of_tendsto_nnreal := NNReal.measurable_of_tendsto end NNReal +namespace EReal + +lemma measurableEmbedding_coe : MeasurableEmbedding Real.toEReal := + isOpenEmbedding_coe.measurableEmbedding + +instance : MeasurableAdd₂ EReal := ⟨EReal.lowerSemicontinuous_add.measurable⟩ + +section MeasurableMul + +variable {α β γ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} {mγ : MeasurableSpace γ} + +lemma measurable_of_real_prod {f : EReal × β → γ} + (h_real : Measurable fun p : ℝ × β ↦ f (p.1, p.2)) + (h_bot : Measurable fun x ↦ f (⊥, x)) (h_top : Measurable fun x ↦ f (⊤, x)) : Measurable f := + .of_union₃_range_cover (measurableEmbedding_prod_mk_left _) (measurableEmbedding_prod_mk_left _) + (measurableEmbedding_coe.prod_mk .id) (by simp [-univ_subset_iff, subset_def, EReal.forall]) + h_bot h_top h_real + +lemma measurable_of_real_real {f : EReal × EReal → β} + (h_real : Measurable fun p : ℝ × ℝ ↦ f (p.1, p.2)) + (h_bot_left : Measurable fun r : ℝ ↦ f (⊥, r)) + (h_top_left : Measurable fun r : ℝ ↦ f (⊤, r)) + (h_bot_right : Measurable fun r : ℝ ↦ f (r, ⊥)) + (h_top_right : Measurable fun r : ℝ ↦ f (r, ⊤)) : + Measurable f := by + refine measurable_of_real_prod ?_ ?_ ?_ + · refine measurable_swap_iff.mp <| measurable_of_real_prod ?_ h_bot_right h_top_right + exact h_real.comp measurable_swap + · exact measurable_of_measurable_real h_bot_left + · exact measurable_of_measurable_real h_top_left + +private lemma measurable_const_mul (c : EReal) : Measurable fun (x : EReal) ↦ c * x := by + refine measurable_of_measurable_real ?_ + have h1 : (fun (p : ℝ) ↦ (⊥ : EReal) * p) + = fun p ↦ if p = 0 then (0 : EReal) else (if p < 0 then ⊤ else ⊥) := by + ext p + split_ifs with h1 h2 + · simp [h1] + · rw [bot_mul_coe_of_neg h2] + · rw [bot_mul_coe_of_pos] + exact lt_of_le_of_ne (not_lt.mp h2) (Ne.symm h1) + have h2 : Measurable fun (p : ℝ) ↦ if p = 0 then (0 : EReal) else if p < 0 then ⊤ else ⊥ := by + refine Measurable.piecewise (measurableSet_singleton _) measurable_const ?_ + exact Measurable.piecewise measurableSet_Iio measurable_const measurable_const + induction c with + | h_bot => rwa [h1] + | h_real c => exact (measurable_id.const_mul _).coe_real_ereal + | h_top => + simp_rw [← neg_bot, neg_mul] + apply Measurable.neg + rwa [h1] + +instance : MeasurableMul₂ EReal := by + refine ⟨measurable_of_real_real ?_ ?_ ?_ ?_ ?_⟩ + · exact (measurable_fst.mul measurable_snd).coe_real_ereal + · exact (measurable_const_mul _).comp measurable_coe_real_ereal + · exact (measurable_const_mul _).comp measurable_coe_real_ereal + · simp_rw [mul_comm _ ⊥] + exact (measurable_const_mul _).comp measurable_coe_real_ereal + · simp_rw [mul_comm _ ⊤] + exact (measurable_const_mul _).comp measurable_coe_real_ereal + +end MeasurableMul + +end EReal + /-- If a function `f : α → ℝ≥0` is measurable and the measure is σ-finite, then there exists spanning measurable sets with finite measure on which `f` is bounded. See also `StronglyMeasurable.exists_spanning_measurableSet_norm_le` for functions into normed diff --git a/Mathlib/MeasureTheory/Constructions/Pi.lean b/Mathlib/MeasureTheory/Constructions/Pi.lean index 670e4e5bf0347..f7a53cd9ee56e 100644 --- a/Mathlib/MeasureTheory/Constructions/Pi.lean +++ b/Mathlib/MeasureTheory/Constructions/Pi.lean @@ -90,7 +90,8 @@ theorem IsCountablySpanning.pi {C : ∀ i, Set (Set (α i))} (hC : ∀ i, IsCoun let e : ℕ → ι → ℕ := fun n => (@decode (ι → ℕ) _ n).iget refine ⟨fun n => Set.pi univ fun i => s i (e n i), fun n => mem_image_of_mem _ fun i _ => h1s i _, ?_⟩ - simp_rw [(surjective_decode_iget (ι → ℕ)).iUnion_comp fun x => Set.pi univ fun i => s i (x i), + simp_rw + [e, (surjective_decode_iget (ι → ℕ)).iUnion_comp fun x => Set.pi univ fun i => s i (x i), iUnion_univ_pi s, h2s, pi_univ] /-- The product of generated σ-algebras is the one generated by boxes, if both generating sets @@ -499,8 +500,8 @@ lemma pi_map_piOptionEquivProd {β : Option ι → Type*} [∀ i, MeasurableSpac simp only [mem_preimage, Set.mem_pi, mem_univ, forall_true_left, mem_prod] refine ⟨by tauto, fun _ i ↦ ?_⟩ rcases i <;> tauto - simp only [me.map_apply, univ_option, le_eq_subset, Finset.prod_insertNone, this, prod_prod, - pi_pi, mul_comm] + simp only [me.map_apply, univ_option, le_eq_subset, Finset.prod_insertNone, this, + prod_prod, pi_pi, mul_comm] section Intervals diff --git a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean index d4071e4ee98fc..cdd41441ac246 100644 --- a/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean +++ b/Mathlib/MeasureTheory/Constructions/Polish/Basic.lean @@ -262,7 +262,7 @@ theorem AnalyticSet.iInter [hι : Nonempty ι] [Countable ι] [T2Space α] {s : choose x hx using A have xt : x ∈ t := by refine mem_iInter.2 fun n => ?_ - simp [hx] + simp [γ, t, F, hx] refine ⟨⟨x, xt⟩, ?_⟩ exact hx i₀ rw [← F_range] @@ -280,7 +280,7 @@ theorem AnalyticSet.iUnion [Countable ι] {s : ι → Set α} (hs : ∀ n, Analy let F : γ → α := fun ⟨n, x⟩ ↦ f n x have F_cont : Continuous F := continuous_sigma f_cont have F_range : range F = ⋃ n, s n := by - simp only [γ, range_sigma_eq_iUnion_range, f_range] + simp only [γ, F, range_sigma_eq_iUnion_range, f_range] rw [← F_range] exact analyticSet_range_of_polishSpace F_cont diff --git a/Mathlib/MeasureTheory/Covering/Besicovitch.lean b/Mathlib/MeasureTheory/Covering/Besicovitch.lean index 1e7a76eadda2d..8d6744400fbbc 100644 --- a/Mathlib/MeasureTheory/Covering/Besicovitch.lean +++ b/Mathlib/MeasureTheory/Covering/Besicovitch.lean @@ -566,7 +566,7 @@ theorem exist_finset_disjoint_balls_large_measure (μ : Measure α) [IsFiniteMea intro x hx obtain ⟨i, y, hxy, h'⟩ : ∃ (i : Fin N) (i_1 : ↥s), i_1 ∈ u i ∧ x ∈ ball (↑i_1) (r ↑i_1) := by - have : x ∈ range a.c := by simpa only [Subtype.range_coe_subtype, setOf_mem_eq] + have : x ∈ range a.c := by simpa only [a, Subtype.range_coe_subtype, setOf_mem_eq] simpa only [mem_iUnion, bex_def] using hu' this refine mem_iUnion.2 ⟨i, ⟨hx, ?_⟩⟩ simp only [v, exists_prop, mem_iUnion, SetCoe.exists, exists_and_right, Subtype.coe_mk] @@ -939,8 +939,8 @@ theorem exists_closedBall_covering_tsum_measure_le (μ : Measure α) [SFinite μ by_cases h'x : x ∈ s' · obtain ⟨i, y, ySi, xy⟩ : ∃ (i : Fin N) (y : ↥s'), y ∈ S i ∧ x ∈ ball (y : α) (r1 y) := by have A : x ∈ range q.c := by - simpa only [not_exists, exists_prop, mem_iUnion, mem_closedBall, not_and, not_le, - mem_setOf_eq, Subtype.range_coe_subtype, mem_diff] using h'x + simpa only [q, not_exists, exists_prop, mem_iUnion, mem_closedBall, not_and, + not_le, mem_setOf_eq, Subtype.range_coe_subtype, mem_diff] using h'x simpa only [mem_iUnion, mem_image, bex_def] using hS A refine mem_iUnion₂.2 ⟨y, Or.inr ?_, ?_⟩ · simp only [mem_iUnion, mem_image] diff --git a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean index 2c3bc40927bd3..e0b6251d52956 100644 --- a/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean +++ b/Mathlib/MeasureTheory/Covering/BesicovitchVectorSpace.lean @@ -6,6 +6,7 @@ Authors: Sébastien Gouëzel import Mathlib.MeasureTheory.Measure.Lebesgue.EqHaar import Mathlib.MeasureTheory.Covering.Besicovitch import Mathlib.Tactic.AdaptationNote +import Mathlib.Algebra.EuclideanDomain.Basic /-! # Satellite configurations for Besicovitch covering lemma in vector spaces diff --git a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean index e0b0eb5f2edfb..86fb861a6a9cb 100644 --- a/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Decomposition/Lebesgue.lean @@ -229,6 +229,18 @@ lemma absolutelyContinuous_withDensity_rnDeriv [HaveLebesgueDecomposition ν μ] · exact measure_mono_null Set.inter_subset_left hνs · exact measure_mono_null Set.inter_subset_right ht2 +lemma AbsolutelyContinuous.withDensity_rnDeriv {ξ : Measure α} [μ.HaveLebesgueDecomposition ν] + (hξμ : ξ ≪ μ) (hξν : ξ ≪ ν) : + ξ ≪ ν.withDensity (μ.rnDeriv ν) := by + conv_rhs at hξμ => rw [μ.haveLebesgueDecomposition_add ν, add_comm] + refine absolutelyContinuous_of_add_of_mutuallySingular hξμ ?_ + exact MutuallySingular.mono_ac (mutuallySingular_singularPart μ ν).symm hξν .rfl + +lemma absolutelyContinuous_withDensity_rnDeriv_swap [ν.HaveLebesgueDecomposition μ] : + ν.withDensity (μ.rnDeriv ν) ≪ μ.withDensity (ν.rnDeriv μ) := + (withDensity_absolutelyContinuous ν (μ.rnDeriv ν)).withDensity_rnDeriv + (absolutelyContinuous_of_le (withDensity_rnDeriv_le _ _)) + lemma singularPart_eq_zero_of_ac (h : μ ≪ ν) : μ.singularPart ν = 0 := by rw [← MutuallySingular.self_iff] exact MutuallySingular.mono_ac (mutuallySingular_singularPart _ _) diff --git a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean index aa7f322d0889d..3896745fc04fb 100644 --- a/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean +++ b/Mathlib/MeasureTheory/Function/ConditionalExpectation/Unique.lean @@ -77,7 +77,7 @@ theorem Lp.ae_eq_zero_of_forall_setIntegral_eq_zero' (hm : m ≤ m0) (f : Lp E' (hf_meas : AEStronglyMeasurable' m f μ) : f =ᵐ[μ] 0 := by let f_meas : lpMeas E' 𝕜 m p μ := ⟨f, hf_meas⟩ -- Porting note: `simp only` does not call `rfl` to try to close the goal. See https://github.com/leanprover-community/mathlib4/issues/5025 - have hf_f_meas : f =ᵐ[μ] f_meas := by simp only [Subtype.coe_mk]; rfl + have hf_f_meas : f =ᵐ[μ] f_meas := by simp only [f_meas, Subtype.coe_mk]; rfl refine hf_f_meas.trans ?_ refine lpMeas.ae_eq_zero_of_forall_setIntegral_eq_zero hm f_meas hp_ne_zero hp_ne_top ?_ ?_ · intro s hs hμs diff --git a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean index 4c9f13b1bf99b..707d7858aebbe 100644 --- a/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean +++ b/Mathlib/MeasureTheory/Function/LpSeminorm/Basic.lean @@ -735,7 +735,7 @@ theorem memℒp_of_bounded [IsFiniteMeasure μ] have hb : ∀ᵐ x ∂μ, f x ≤ b := h.mono fun ω h => h.2 (memℒp_const (max |a| |b|)).mono' hX (by filter_upwards [ha, hb] with x using abs_le_max_abs_abs) -@[mono] +@[gcongr, mono] theorem eLpNorm'_mono_measure (f : α → F) (hμν : ν ≤ μ) (hq : 0 ≤ q) : eLpNorm' f q ν ≤ eLpNorm' f q μ := by simp_rw [eLpNorm'] @@ -745,7 +745,7 @@ theorem eLpNorm'_mono_measure (f : α → F) (hμν : ν ≤ μ) (hq : 0 ≤ q) @[deprecated (since := "2024-07-27")] alias snorm'_mono_measure := eLpNorm'_mono_measure -@[mono] +@[gcongr, mono] theorem eLpNormEssSup_mono_measure (f : α → F) (hμν : ν ≪ μ) : eLpNormEssSup f ν ≤ eLpNormEssSup f μ := by simp_rw [eLpNormEssSup] @@ -754,7 +754,7 @@ theorem eLpNormEssSup_mono_measure (f : α → F) (hμν : ν ≪ μ) : @[deprecated (since := "2024-07-27")] alias snormEssSup_mono_measure := eLpNormEssSup_mono_measure -@[mono] +@[gcongr, mono] theorem eLpNorm_mono_measure (f : α → F) (hμν : ν ≤ μ) : eLpNorm f p ν ≤ eLpNorm f p μ := by by_cases hp0 : p = 0 · simp [hp0] diff --git a/Mathlib/MeasureTheory/Function/LpSpace.lean b/Mathlib/MeasureTheory/Function/LpSpace.lean index ca21a90b697cf..7d6a28d6d78b1 100644 --- a/Mathlib/MeasureTheory/Function/LpSpace.lean +++ b/Mathlib/MeasureTheory/Function/LpSpace.lean @@ -1479,7 +1479,7 @@ private theorem eLpNorm'_sum_norm_sub_le_tsum_of_cauchy_eLpNorm' {f : ℕ → α ∀ n, (fun x => ∑ i ∈ Finset.range (n + 1), ‖f (i + 1) x - f i x‖) = ∑ i ∈ Finset.range (n + 1), f_norm_diff i := - fun n => funext fun x => by simp + fun n => funext fun x => by simp [f_norm_diff] rw [hgf_norm_diff] refine (eLpNorm'_sum_le (fun i _ => ((hf (i + 1)).sub (hf i)).norm) hp1).trans ?_ simp_rw [eLpNorm'_norm] @@ -1508,9 +1508,6 @@ private theorem lintegral_rpow_sum_coe_nnnorm_sub_le_rpow_tsum · rw [Real.norm_of_nonneg _] exact Finset.sum_nonneg fun x _ => norm_nonneg _ · exact fun x _ => norm_nonneg _ - change - (∫⁻ a, (fun x => ↑‖∑ i ∈ Finset.range (n + 1), ‖f (i + 1) x - f i x‖‖₊ ^ p) a ∂μ) ^ p⁻¹ ≤ - ∑' i, B i at hn rwa [h_nnnorm_nonneg] at hn private theorem lintegral_rpow_tsum_coe_nnnorm_sub_le_tsum {f : ℕ → α → E} diff --git a/Mathlib/MeasureTheory/Function/SimpleFunc.lean b/Mathlib/MeasureTheory/Function/SimpleFunc.lean index 74809c39984b2..f8ef14327a38d 100644 --- a/Mathlib/MeasureTheory/Function/SimpleFunc.lean +++ b/Mathlib/MeasureTheory/Function/SimpleFunc.lean @@ -665,7 +665,7 @@ theorem mem_image_of_mem_range_restrict {r : β} {s : Set α} {f : α →ₛ β} rw [restrict_of_not_measurable hs] at hr exact (h0 <| eq_zero_of_mem_range_zero hr).elim -@[mono] +@[gcongr, mono] theorem restrict_mono [Preorder β] (s : Set α) {f g : α →ₛ β} (H : f ≤ g) : f.restrict s ≤ g.restrict s := if hs : MeasurableSet s then fun x => by diff --git a/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean b/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean index 4f7644744e85c..72cc5e33e2df2 100644 --- a/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean +++ b/Mathlib/MeasureTheory/Group/GeometryOfNumbers.lean @@ -135,6 +135,6 @@ theorem exists_ne_zero_mem_lattice_of_measure_mul_two_pow_le_measure [NormedAddC refine (mul_lt_mul_right h_mes (ne_of_lt h_cpt.measure_lt_top)).mpr ?_ rw [ofReal_pow (NNReal.coe_nonneg _)] refine one_lt_pow₀ ?_ (ne_of_gt finrank_pos) - simp [(exists_seq_strictAnti_tendsto (0 : ℝ≥0)).choose_spec.2.1 n] + simp [u, K, S, Z, (exists_seq_strictAnti_tendsto (0 : ℝ≥0)).choose_spec.2.1 n] end MeasureTheory diff --git a/Mathlib/MeasureTheory/Group/Measure.lean b/Mathlib/MeasureTheory/Group/Measure.lean index 8662ff3b7f53c..449597022125a 100644 --- a/Mathlib/MeasureTheory/Group/Measure.lean +++ b/Mathlib/MeasureTheory/Group/Measure.lean @@ -764,7 +764,12 @@ nonrec theorem _root_.MulEquiv.isHaarMeasure_map [BorelSpace G] [TopologicalGrou [TopologicalGroup H] (e : G ≃* H) (he : Continuous e) (hesymm : Continuous e.symm) : IsHaarMeasure (Measure.map e μ) := let f : G ≃ₜ H := .mk e - isHaarMeasure_map μ e he e.surjective f.isClosedEmbedding.tendsto_cocompact + #adaptation_note + /-- + After https://github.com/leanprover/lean4/pull/6024 + we needed to write `e.toMonoidHom` instead of just `e`, to avoid unification issues. + -/ + isHaarMeasure_map μ e.toMonoidHom he e.surjective f.isClosedEmbedding.tendsto_cocompact /-- A convenience wrapper for MeasureTheory.Measure.isAddHaarMeasure_map`. -/ instance _root_.ContinuousLinearEquiv.isAddHaarMeasure_map diff --git a/Mathlib/MeasureTheory/Group/Prod.lean b/Mathlib/MeasureTheory/Group/Prod.lean index a33b49bf00b01..db452a55297de 100644 --- a/Mathlib/MeasureTheory/Group/Prod.lean +++ b/Mathlib/MeasureTheory/Group/Prod.lean @@ -34,7 +34,7 @@ Note that this theory only applies in measurable groups, i.e., when multiplicati are measurable. This is not the case in general in locally compact groups, or even in compact groups, when the topology is not second-countable. For arguments along the same line, but using continuous functions instead of measurable sets and working in the general locally compact -setting, see the file `MeasureTheory.Measure.Haar.Unique.lean`. +setting, see the file `Mathlib/MeasureTheory/Measure/Haar/Unique.lean`. -/ diff --git a/Mathlib/MeasureTheory/Integral/Bochner.lean b/Mathlib/MeasureTheory/Integral/Bochner.lean index a3a28a6bca1d4..65a635f05396d 100644 --- a/Mathlib/MeasureTheory/Integral/Bochner.lean +++ b/Mathlib/MeasureTheory/Integral/Bochner.lean @@ -1168,7 +1168,8 @@ lemma integral_tendsto_of_tendsto_of_monotone {μ : Measure α} {f : ℕ → α simp [f', ha (zero_le n)] have hf'_meas : ∀ n, Integrable (f' n) μ := fun n ↦ (hf n).sub (hf 0) suffices Tendsto (fun n ↦ ∫ x, f' n x ∂μ) atTop (𝓝 (∫ x, (F - f 0) x ∂μ)) by - simp_rw [integral_sub (hf _) (hf _), integral_sub' hF (hf 0), tendsto_sub_const_iff] at this + simp_rw [f', integral_sub (hf _) (hf _), integral_sub' hF (hf 0), + tendsto_sub_const_iff] at this exact this have hF_ge : 0 ≤ᵐ[μ] fun x ↦ (F - f 0) x := by filter_upwards [h_tendsto, h_mono] with x hx_tendsto hx_mono @@ -1334,7 +1335,7 @@ theorem integral_mono_ae {f g : α → ℝ} (hf : Integrable f μ) (hg : Integra exact setToFun_mono (dominatedFinMeasAdditive_weightedSMul μ) (fun s _ _ => weightedSMul_nonneg s) hf hg h -@[mono] +@[gcongr, mono] theorem integral_mono {f g : α → ℝ} (hf : Integrable f μ) (hg : Integrable g μ) (h : f ≤ g) : ∫ a, f a ∂μ ≤ ∫ a, g a ∂μ := integral_mono_ae hf hg <| Eventually.of_forall h diff --git a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean index 9740edb400613..a326a634d81ca 100644 --- a/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean +++ b/Mathlib/MeasureTheory/Integral/DominatedConvergence.lean @@ -589,7 +589,7 @@ theorem continuous_parametric_primitive_of_continuous (uIcc_subset_Icc ⟨a_lt.1.le, lt_b.1.le⟩ ⟨a_lt.2.le, lt_b.2.le⟩) exact Eventually.of_forall this _ ≤ ∫ t in Icc (b₀ - δ) (b₀ + δ), M + 1 ∂μ + ∫ _t in Icc a b, δ ∂μ := by - gcongr + gcongr ?_ + ?_ · apply setIntegral_mono_on · exact (hf.uncurry_left _).norm.integrableOn_Icc · exact continuous_const.integrableOn_Icc diff --git a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean index 6870c55e4e416..67c398ceac956 100644 --- a/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean +++ b/Mathlib/MeasureTheory/Integral/IntervalIntegral.lean @@ -6,6 +6,7 @@ Authors: Yury Kudryashov, Patrick Massot, Sébastien Gouëzel import Mathlib.Order.Interval.Set.Disjoint import Mathlib.MeasureTheory.Integral.SetIntegral import Mathlib.MeasureTheory.Measure.Lebesgue.Basic +import Mathlib.Algebra.EuclideanDomain.Basic /-! # Integral over an interval @@ -85,6 +86,11 @@ theorem intervalIntegrable_iff : IntervalIntegrable f μ a b ↔ IntegrableOn f theorem IntervalIntegrable.def' (h : IntervalIntegrable f μ a b) : IntegrableOn f (Ι a b) μ := intervalIntegrable_iff.mp h +theorem IntervalIntegrable.congr {g : ℝ → E} (hf : IntervalIntegrable f μ a b) + (h : f =ᵐ[μ.restrict (Ι a b)] g) : + IntervalIntegrable g μ a b := by + rwa [intervalIntegrable_iff, ← integrableOn_congr_fun_ae h, ← intervalIntegrable_iff] + 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] diff --git a/Mathlib/MeasureTheory/Integral/Lebesgue.lean b/Mathlib/MeasureTheory/Integral/Lebesgue.lean index aff81c505d96f..e5d534014c897 100644 --- a/Mathlib/MeasureTheory/Integral/Lebesgue.lean +++ b/Mathlib/MeasureTheory/Integral/Lebesgue.lean @@ -78,7 +78,7 @@ theorem SimpleFunc.lintegral_eq_lintegral {m : MeasurableSpace α} (f : α → exact le_antisymm (iSup₂_le fun g hg => lintegral_mono hg <| le_rfl) (le_iSup₂_of_le f le_rfl le_rfl) -@[mono] +@[gcongr, mono] theorem lintegral_mono' {m : MeasurableSpace α} ⦃μ ν : Measure α⦄ (hμν : μ ≤ ν) ⦃f g : α → ℝ≥0∞⦄ (hfg : f ≤ g) : ∫⁻ a, f a ∂μ ≤ ∫⁻ a, g a ∂ν := by rw [lintegral, lintegral] diff --git a/Mathlib/MeasureTheory/Integral/Marginal.lean b/Mathlib/MeasureTheory/Integral/Marginal.lean index 4e19390aa37fb..2c027ef3bc5e7 100644 --- a/Mathlib/MeasureTheory/Integral/Marginal.lean +++ b/Mathlib/MeasureTheory/Integral/Marginal.lean @@ -122,8 +122,9 @@ theorem lmarginal_singleton (f : (∀ i, π i) → ℝ≥0∞) (i : δ) : ext1 x calc (∫⋯∫⁻_{i}, f ∂μ) x = ∫⁻ (y : π (default : α)), f (updateFinset x {i} (e y)) ∂μ (default : α) := by - simp_rw [lmarginal, measurePreserving_piUnique (fun j : ({i} : Finset δ) ↦ μ j) |>.symm _ - |>.lintegral_map_equiv] + simp_rw [lmarginal, + measurePreserving_piUnique (fun j : ({i} : Finset δ) ↦ μ j) |>.symm _ + |>.lintegral_map_equiv] _ = ∫⁻ xᵢ, f (Function.update x i xᵢ) ∂μ i := by simp [update_eq_updateFinset]; rfl variable {μ} in diff --git a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean index 424952fb5cb92..1cfbb6e4f677d 100644 --- a/Mathlib/MeasureTheory/Integral/MeanInequalities.lean +++ b/Mathlib/MeasureTheory/Integral/MeanInequalities.lean @@ -221,7 +221,7 @@ theorem lintegral_prod_norm_pow_le {α ι : Type*} [MeasurableSpace α] {μ : Me calc ∫⁻ a, ∏ i ∈ insert i₀ s, f i a ^ p i ∂μ = ∫⁻ a, f i₀ a ^ p i₀ * ∏ i ∈ s, f i a ^ p i ∂μ := by simp [hi₀] _ = ∫⁻ a, f i₀ a ^ p i₀ * (∏ i ∈ s, f i a ^ q i) ^ (1 - p i₀) ∂μ := by - simp [← ENNReal.prod_rpow_of_nonneg hpi₀, ← ENNReal.rpow_mul, + simp [q, ← ENNReal.prod_rpow_of_nonneg hpi₀, ← ENNReal.rpow_mul, div_mul_cancel₀ (h := h2pi₀)] _ ≤ (∫⁻ a, f i₀ a ∂μ) ^ p i₀ * (∫⁻ a, ∏ i ∈ s, f i a ^ q i ∂μ) ^ (1 - p i₀) := by apply ENNReal.lintegral_mul_norm_pow_le @@ -234,7 +234,7 @@ theorem lintegral_prod_norm_pow_le {α ι : Type*} [MeasurableSpace α] {μ : Me gcongr -- behavior of gcongr is heartbeat-dependent, which makes code really fragile... exact ih (fun i hi ↦ hf i <| mem_insert_of_mem hi) hq h2q _ = (∫⁻ a, f i₀ a ∂μ) ^ p i₀ * ∏ i ∈ s, (∫⁻ a, f i a ∂μ) ^ p i := by - simp [← ENNReal.prod_rpow_of_nonneg hpi₀, ← ENNReal.rpow_mul, + simp [q, ← ENNReal.prod_rpow_of_nonneg hpi₀, ← ENNReal.rpow_mul, div_mul_cancel₀ (h := h2pi₀)] _ = ∏ i ∈ insert i₀ s, (∫⁻ a, f i a ∂μ) ^ p i := by simp [hi₀] diff --git a/Mathlib/MeasureTheory/Integral/SetToL1.lean b/Mathlib/MeasureTheory/Integral/SetToL1.lean index 2a0d2d70bd546..7c6e7f8e1b323 100644 --- a/Mathlib/MeasureTheory/Integral/SetToL1.lean +++ b/Mathlib/MeasureTheory/Integral/SetToL1.lean @@ -1365,7 +1365,7 @@ theorem tendsto_setToFun_of_L1 (hT : DominatedFinMeasAdditive μ T C) {ι} (f : filter_upwards [hfsi] with i hi refine lintegral_congr_ae ?_ filter_upwards [hi.coeFn_toL1, hfi.coeFn_toL1] with x hxi hxf - simp_rw [F_lp, dif_pos hi, hxi, hxf] + simp_rw [F_lp, dif_pos hi, hxi, f_lp, hxf] suffices Tendsto (fun i => setToFun μ T hT (F_lp i)) l (𝓝 (setToFun μ T hT f)) by refine (tendsto_congr' ?_).mp this filter_upwards [hfsi] with i hi diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean index 678a6983571d0..f0a6159c042b5 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Basic.lean @@ -4,14 +4,16 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ import Mathlib.Data.Finset.Update -import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Data.Int.Cast.Pi +import Mathlib.Data.Nat.Cast.Basic import Mathlib.Data.Prod.TProd import Mathlib.Data.Set.UnionLift import Mathlib.GroupTheory.Coset.Defs import Mathlib.MeasureTheory.MeasurableSpace.Instances import Mathlib.Order.Filter.SmallSets -import Mathlib.Tactic.FinCases import Mathlib.Order.LiminfLimsup +import Mathlib.Order.Filter.AtTopBot.CountablyGenerated +import Mathlib.Tactic.FinCases /-! # Measurable spaces and measurable functions diff --git a/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean b/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean index 62141d5c9d30c..12eef5dd443c3 100644 --- a/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean +++ b/Mathlib/MeasureTheory/MeasurableSpace/Embedding.lean @@ -506,9 +506,16 @@ def arrowProdEquivProdArrow (α β γ : Type*) [MeasurableSpace α] [MeasurableS __ := Equiv.arrowProdEquivProdArrow α β γ measurable_toFun _ h := by simp_rw [Equiv.arrowProdEquivProdArrow, coe_fn_mk] + #adaptation_note + /-- + After https://github.com/leanprover/lean4/pull/6024 + we need provide the type hints `(a : γ → α × β)`, to avoid unification issues. + -/ exact MeasurableSet.preimage h (Measurable.prod_mk - (measurable_pi_lambda (fun a c ↦ (a c).1) fun a ↦ (measurable_pi_apply a).fst) - (measurable_pi_lambda (fun a c ↦ (a c).2) fun a ↦ (measurable_pi_apply a).snd )) + (measurable_pi_lambda (fun (a : γ → α × β) c ↦ (a c).1) + fun a ↦ (measurable_pi_apply a).fst) + (measurable_pi_lambda (fun (a : γ → α × β) c ↦ (a c).2) + fun a ↦ (measurable_pi_apply a).snd)) measurable_invFun _ h := by simp_rw [Equiv.arrowProdEquivProdArrow, coe_fn_symm_mk] exact MeasurableSet.preimage h (by measurability) @@ -715,7 +722,7 @@ noncomputable def schroederBernstein {f : α → β} {g : β → α} (hf : Measu have : Aᶜ = g '' Bᶜ := by apply compl_injective rw [← Afp] - simp + simp [F, B] rw [this] exact (hg.equivImage _).symm have Fmono : ∀ {A B}, A ⊆ B → F A ⊆ F B := fun h => diff --git a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean index c159b4c1db9d1..655b839adfe70 100644 --- a/Mathlib/MeasureTheory/Measure/AEMeasurable.lean +++ b/Mathlib/MeasureTheory/Measure/AEMeasurable.lean @@ -194,7 +194,7 @@ theorem exists_ae_eq_range_subset (H : AEMeasurable f μ) {t : Set β} (ht : ∀ exact H.ae_eq_mk.and ht filter_upwards [compl_mem_ae_iff.2 A] with x hx rw [mem_compl_iff] at hx - simp only [g, hx, piecewise_eq_of_not_mem, not_false_iff] + simp only [s, g, hx, piecewise_eq_of_not_mem, not_false_iff] contrapose! hx apply subset_toMeasurable simp only [hx, mem_compl_iff, mem_setOf_eq, false_and, not_false_iff] diff --git a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean index 1b17d6219d497..babc5786d359e 100644 --- a/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean +++ b/Mathlib/MeasureTheory/Measure/FiniteMeasure.lean @@ -411,10 +411,7 @@ theorem continuous_testAgainstNN_eval (f : Ω →ᵇ ℝ≥0) : Continuous fun μ : FiniteMeasure Ω ↦ μ.testAgainstNN f := by show Continuous ((fun φ : WeakDual ℝ≥0 (Ω →ᵇ ℝ≥0) ↦ φ f) ∘ toWeakDualBCNN) refine Continuous.comp ?_ (toWeakDualBCNN_continuous (Ω := Ω)) - exact WeakBilin.eval_continuous (𝕜 := ℝ≥0) (E := (Ω →ᵇ ℝ≥0) →L[ℝ≥0] ℝ≥0) _ _ - /- porting note: without explicitly providing `𝕜` and `E` TC synthesis times - out trying to find `Module ℝ≥0 ((Ω →ᵇ ℝ≥0) →L[ℝ≥0] ℝ≥0)`, but it can find it with enough time: - `set_option synthInstance.maxHeartbeats 47000` was sufficient. -/ + exact WeakBilin.eval_continuous _ _ /-- The total mass of a finite measure depends continuously on the measure. -/ theorem continuous_mass : Continuous fun μ : FiniteMeasure Ω ↦ μ.mass := by diff --git a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean index 546c35be2dda7..caed697da9d50 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Basic.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Basic.lean @@ -34,7 +34,7 @@ where `ᵒ` denotes the interior. We also give a form of uniqueness of Haar measure, for σ-finite measures on second-countable locally compact groups. For more involved statements not assuming second-countability, see -the file `MeasureTheory.Measure.Haar.Unique`. +the file `Mathlib/MeasureTheory/Measure/Haar/Unique.lean`. ## Main Declarations @@ -626,7 +626,7 @@ bypass all topological arguments, and conclude using uniqueness of σ-finite lef in measurable groups. For more general uniqueness statements without second-countability assumptions, -see the file `MeasureTheory.Measure.Haar.Unique`. +see the file `Mathlib/MeasureTheory/Measure/Haar/Unique.lean`. -/ variable [SecondCountableTopology G] diff --git a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean index 9f84eee98f624..c9da154064847 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/OfBasis.lean @@ -105,14 +105,14 @@ theorem parallelepiped_orthonormalBasis_one_dim (b : OrthonormalBasis ι ℝ ℝ · intro x hx refine ⟨x 0, ⟨hx.1 0, hx.2 0⟩, ?_⟩ ext j - simp only [Subsingleton.elim j 0] + simp only [F, Subsingleton.elim j 0] · rintro x ⟨y, hy, rfl⟩ exact ⟨fun _j => hy.1, fun _j => hy.2⟩ rcases orthonormalBasis_one_dim (b.reindex e) with (H | H) · left simp_rw [parallelepiped, H, A, Algebra.id.smul_eq_mul, mul_one] - simp only [Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton, ← image_comp, - Function.comp_apply, image_id'] + simp only [F, Finset.univ_unique, Fin.default_eq_zero, Finset.sum_singleton, + ← image_comp, Function.comp_apply, image_id'] · right simp_rw [H, parallelepiped, Algebra.id.smul_eq_mul, A] simp only [F, Finset.univ_unique, Fin.default_eq_zero, mul_neg, mul_one, Finset.sum_neg_distrib, diff --git a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean index afd7790d82993..e9d2e87202f9e 100644 --- a/Mathlib/MeasureTheory/Measure/Haar/Unique.lean +++ b/Mathlib/MeasureTheory/Measure/Haar/Unique.lean @@ -58,7 +58,7 @@ measure. We follow McQuillan's answer at https://mathoverflow.net/questions/4566 On second-countable groups, one can arrive to slightly different uniqueness results by using that the operations are measurable. In particular, one can get uniqueness assuming σ-finiteness of the measures but discarding the assumption that they are finite on compact sets. See -`haarMeasure_unique` in the file `MeasureTheory.Measure.Haar.Basic`. +`haarMeasure_unique` in the file `Mathlib/MeasureTheory/Measure/Haar/Basic.lean`. ## References @@ -169,7 +169,7 @@ lemma integral_isMulLeftInvariant_isMulRightInvariant_combo calc ∫ x, f x ∂μ = ∫ x, f x * (D x)⁻¹ * D x ∂μ := by congr with x; rw [mul_assoc, inv_mul_cancel₀ (D_pos x).ne', mul_one] - _ = ∫ x, (∫ y, f x * (D x)⁻¹ * g (y⁻¹ * x) ∂ν) ∂μ := by simp_rw [integral_mul_left] + _ = ∫ x, (∫ y, f x * (D x)⁻¹ * g (y⁻¹ * x) ∂ν) ∂μ := by simp_rw [D, integral_mul_left] _ = ∫ y, (∫ x, f x * (D x)⁻¹ * g (y⁻¹ * x) ∂μ) ∂ν := by apply integral_integral_swap_of_hasCompactSupport · apply Continuous.mul diff --git a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean index be988e8efe5a8..fc756040cc012 100644 --- a/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean +++ b/Mathlib/MeasureTheory/Measure/Lebesgue/VolumeOfBalls.lean @@ -3,10 +3,11 @@ Copyright (c) 2023 Xavier Roblot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Xavier Roblot -/ +import Mathlib.Analysis.SpecialFunctions.Gamma.BohrMollerup +import Mathlib.Data.Complex.FiniteDimensional import Mathlib.MeasureTheory.Constructions.HaarToSphere import Mathlib.MeasureTheory.Integral.Gamma import Mathlib.MeasureTheory.Integral.Pi -import Mathlib.Analysis.SpecialFunctions.Gamma.BohrMollerup /-! # Volume of balls @@ -206,7 +207,7 @@ theorem MeasureTheory.volume_sum_rpow_lt [Nonempty ι] {p : ℝ} (hp : 1 ≤ p) ext x refine ⟨fun hx => ?_, fun hx => hx.elim⟩ exact not_le.mpr (lt_of_lt_of_le (Set.mem_setOf.mp hx) hr) (h₂ x) - rw [this, measure_empty, ← zero_eq_ofReal.mpr hr, zero_pow Fin.size_pos'.ne', zero_mul] + rw [this, measure_empty, ← zero_eq_ofReal.mpr hr, zero_pow Fin.pos'.ne', zero_mul] · rw [← volume_sum_rpow_lt_one _ hp, ← ofReal_pow (le_of_lt hr), ← finrank_pi ℝ] convert addHaar_smul_of_nonneg volume (le_of_lt hr) {x : ι → ℝ | ∑ i, |x i| ^ p < 1} using 2 simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hr), Set.preimage_setOf_eq, Pi.smul_apply, @@ -279,7 +280,7 @@ theorem Complex.volume_sum_rpow_lt [Nonempty ι] {p : ℝ} (hp : 1 ≤ p) (r : ext x refine ⟨fun hx => ?_, fun hx => hx.elim⟩ exact not_le.mpr (lt_of_lt_of_le (Set.mem_setOf.mp hx) hr) (h₂ x) - rw [this, measure_empty, ← zero_eq_ofReal.mpr hr, zero_pow Fin.size_pos'.ne', zero_mul] + rw [this, measure_empty, ← zero_eq_ofReal.mpr hr, zero_pow Fin.pos'.ne', zero_mul] · rw [← Complex.volume_sum_rpow_lt_one _ hp, ← ENNReal.ofReal_pow (le_of_lt hr)] convert addHaar_smul_of_nonneg volume (le_of_lt hr) {x : ι → ℂ | ∑ i, ‖x i‖ ^ p < 1} using 2 · simp_rw [← Set.preimage_smul_inv₀ (ne_of_gt hr), Set.preimage_setOf_eq, Pi.smul_apply, diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean index 3d62ba5101860..92a5dcb5aa47b 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpace.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpace.lean @@ -1015,6 +1015,70 @@ instance instCompleteLattice {_ : MeasurableSpace α} : CompleteLattice (Measure end sInf +lemma inf_apply {s : Set α} (hs : MeasurableSet s) : + (μ ⊓ ν) s = sInf {m | ∃ t, m = μ (t ∩ s) + ν (tᶜ ∩ s)} := by + -- `(μ ⊓ ν) s` is defined as `⊓ (t : ℕ → Set α) (ht : s ⊆ ⋃ n, t n), ∑' n, μ (t n) ⊓ ν (t n)` + rw [← sInf_pair, Measure.sInf_apply hs, OuterMeasure.sInf_apply + (image_nonempty.2 <| insert_nonempty μ {ν})] + refine le_antisymm (le_sInf fun m ⟨t, ht₁⟩ ↦ ?_) (le_iInf₂ fun t' ht' ↦ ?_) + · subst ht₁ + -- We first show `(μ ⊓ ν) s ≤ μ (t ∩ s) + ν (tᶜ ∩ s)` for any `t : Set α` + -- For this, define the sequence `t' : ℕ → Set α` where `t' 0 = t ∩ s`, `t' 1 = tᶜ ∩ s` and + -- `∅` otherwise. Then, we have by construction + -- `(μ ⊓ ν) s ≤ ∑' n, μ (t' n) ⊓ ν (t' n) ≤ μ (t' 0) + ν (t' 1) = μ (t ∩ s) + ν (tᶜ ∩ s)`. + set t' : ℕ → Set α := fun n ↦ if n = 0 then t ∩ s else if n = 1 then tᶜ ∩ s else ∅ with ht' + refine (iInf₂_le t' fun x hx ↦ ?_).trans ?_ + · by_cases hxt : x ∈ t + · refine mem_iUnion.2 ⟨0, ?_⟩ + simp [hx, hxt] + · refine mem_iUnion.2 ⟨1, ?_⟩ + simp [hx, hxt] + · simp only [iInf_image, coe_toOuterMeasure, iInf_pair] + rw [tsum_eq_add_tsum_ite 0, tsum_eq_add_tsum_ite 1, if_neg zero_ne_one.symm, + (tsum_eq_zero_iff ENNReal.summable).2 _, add_zero] + · exact add_le_add (inf_le_left.trans <| by simp [ht']) (inf_le_right.trans <| by simp [ht']) + · simp only [ite_eq_left_iff] + intro n hn₁ hn₀ + simp only [ht', if_neg hn₀, if_neg hn₁, measure_empty, iInf_pair, le_refl, inf_of_le_left] + · simp only [iInf_image, coe_toOuterMeasure, iInf_pair] + -- Conversely, fixing `t' : ℕ → Set α` such that `s ⊆ ⋃ n, t' n`, we construct `t : Set α` + -- for which `μ (t ∩ s) + ν (tᶜ ∩ s) ≤ ∑' n, μ (t' n) ⊓ ν (t' n)`. + -- Denoting `I := {n | μ (t' n) ≤ ν (t' n)}`, we set `t = ⋃ n ∈ I, t' n`. + -- Clearly `μ (t ∩ s) ≤ ∑' n ∈ I, μ (t' n)` and `ν (tᶜ ∩ s) ≤ ∑' n ∉ I, ν (t' n)`, so + -- `μ (t ∩ s) + ν (tᶜ ∩ s) ≤ ∑' n ∈ I, μ (t' n) + ∑' n ∉ I, ν (t' n)` + -- where the RHS equals `∑' n, μ (t' n) ⊓ ν (t' n)` by the choice of `I`. + set t := ⋃ n ∈ {k : ℕ | μ (t' k) ≤ ν (t' k)}, t' n with ht + suffices hadd : μ (t ∩ s) + ν (tᶜ ∩ s) ≤ ∑' n, μ (t' n) ⊓ ν (t' n) by + exact le_trans (sInf_le ⟨t, rfl⟩) hadd + have hle₁ : μ (t ∩ s) ≤ ∑' (n : {k | μ (t' k) ≤ ν (t' k)}), μ (t' n) := + (measure_mono inter_subset_left).trans <| measure_biUnion_le _ (to_countable _) _ + have hcap : tᶜ ∩ s ⊆ ⋃ n ∈ {k | ν (t' k) < μ (t' k)}, t' n := by + simp_rw [ht, compl_iUnion] + refine fun x ⟨hx₁, hx₂⟩ ↦ mem_iUnion₂.2 ?_ + obtain ⟨i, hi⟩ := mem_iUnion.1 <| ht' hx₂ + refine ⟨i, ?_, hi⟩ + by_contra h + simp only [mem_setOf_eq, not_lt] at h + exact mem_iInter₂.1 hx₁ i h hi + have hle₂ : ν (tᶜ ∩ s) ≤ ∑' (n : {k | ν (t' k) < μ (t' k)}), ν (t' n) := + (measure_mono hcap).trans (measure_biUnion_le ν (to_countable {k | ν (t' k) < μ (t' k)}) _) + refine (add_le_add hle₁ hle₂).trans ?_ + have heq : {k | μ (t' k) ≤ ν (t' k)} ∪ {k | ν (t' k) < μ (t' k)} = univ := by + ext k; simp [le_or_lt] + conv in ∑' (n : ℕ), μ (t' n) ⊓ ν (t' n) => rw [← tsum_univ, ← heq] + rw [tsum_union_disjoint (f := fun n ↦ μ (t' n) ⊓ ν (t' n)) ?_ ENNReal.summable ENNReal.summable] + · refine add_le_add (tsum_congr ?_).le (tsum_congr ?_).le + · rw [Subtype.forall] + intro n hn; simpa + · rw [Subtype.forall] + intro n hn + rw [mem_setOf_eq] at hn + simp [le_of_lt hn] + · rw [Set.disjoint_iff] + rintro k ⟨hk₁, hk₂⟩ + rw [mem_setOf_eq] at hk₁ hk₂ + exact False.elim <| hk₂.not_le hk₁ + @[simp] theorem _root_.MeasureTheory.OuterMeasure.toMeasure_top : (⊤ : OuterMeasure α).toMeasure (by rw [OuterMeasure.top_caratheodory]; exact le_top) = diff --git a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean index 11481cc61993f..a05138dd08fce 100644 --- a/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean +++ b/Mathlib/MeasureTheory/Measure/MeasureSpaceDef.lean @@ -296,8 +296,6 @@ theorem subset_toMeasurable (μ : Measure α) (s : Set α) : s ⊆ toMeasurable theorem ae_le_toMeasurable : s ≤ᵐ[μ] toMeasurable μ s := HasSubset.Subset.eventuallyLE (subset_toMeasurable _ _) - --(subset_toMeasurable _ _).EventuallyLE - @[simp] theorem measurableSet_toMeasurable (μ : Measure α) (s : Set α) : MeasurableSet (toMeasurable μ s) := by diff --git a/Mathlib/MeasureTheory/Measure/MutuallySingular.lean b/Mathlib/MeasureTheory/Measure/MutuallySingular.lean index 257f1ecc3765f..92ae8dd6e234a 100644 --- a/Mathlib/MeasureTheory/Measure/MutuallySingular.lean +++ b/Mathlib/MeasureTheory/Measure/MutuallySingular.lean @@ -24,7 +24,7 @@ measure, mutually singular open Set -open MeasureTheory NNReal ENNReal +open MeasureTheory NNReal ENNReal Filter namespace MeasureTheory @@ -89,6 +89,10 @@ theorem mono_ac (h : μ₁ ⟂ₘ ν₁) (hμ : μ₂ ≪ μ₁) (hν : ν₂ let ⟨s, hs, h₁, h₂⟩ := h ⟨s, hs, hμ h₁, hν h₂⟩ +lemma congr_ac (hμμ₂ : μ ≪ μ₂) (hμ₂μ : μ₂ ≪ μ) (hνν₂ : ν ≪ ν₂) (hν₂ν : ν₂ ≪ ν) : + μ ⟂ₘ ν ↔ μ₂ ⟂ₘ ν₂ := + ⟨fun h ↦ h.mono_ac hμ₂μ hν₂ν, fun h ↦ h.mono_ac hμμ₂ hνν₂⟩ + theorem mono (h : μ₁ ⟂ₘ ν₁) (hμ : μ₂ ≤ μ₁) (hν : ν₂ ≤ ν₁) : μ₂ ⟂ₘ ν₂ := h.mono_ac hμ.absolutelyContinuous hν.absolutelyContinuous @@ -146,6 +150,23 @@ lemma eq_zero_of_absolutelyContinuous_of_mutuallySingular {μ ν : Measure α} rw [← Measure.MutuallySingular.self_iff] exact h_ms.mono_ac Measure.AbsolutelyContinuous.rfl h_ac +lemma absolutelyContinuous_of_add_of_mutuallySingular {ν₁ ν₂ : Measure α} + (h : μ ≪ ν₁ + ν₂) (h_ms : μ ⟂ₘ ν₂) : μ ≪ ν₁ := by + refine AbsolutelyContinuous.mk fun s hs hs_zero ↦ ?_ + let t := h_ms.nullSet + have ht : MeasurableSet t := h_ms.measurableSet_nullSet + have htμ : μ t = 0 := h_ms.measure_nullSet + have htν₂ : ν₂ tᶜ = 0 := h_ms.measure_compl_nullSet + have : μ s = μ (s ∩ tᶜ) := by + conv_lhs => rw [← inter_union_compl s t] + rw [measure_union, measure_inter_null_of_null_right _ htμ, zero_add] + · exact (disjoint_compl_right.inter_right' _ ).inter_left' _ + · exact hs.inter ht.compl + rw [this] + refine h ?_ + simp only [Measure.coe_add, Pi.add_apply, add_eq_zero] + exact ⟨measure_inter_null_of_null_left _ hs_zero, measure_inter_null_of_null_right _ htν₂⟩ + lemma _root_.MeasurableEmbedding.mutuallySingular_map {β : Type*} {_ : MeasurableSpace β} {f : α → β} (hf : MeasurableEmbedding f) (hμν : μ ⟂ₘ ν) : μ.map f ⟂ₘ ν.map f := by @@ -153,6 +174,118 @@ lemma _root_.MeasurableEmbedding.mutuallySingular_map {β : Type*} {_ : Measurab · rw [hf.map_apply, hf.injective.preimage_image, hμν.measure_nullSet] · rw [hf.map_apply, Set.preimage_compl, hf.injective.preimage_image, hμν.measure_compl_nullSet] +lemma exists_null_set_measure_lt_of_disjoint (h : Disjoint μ ν) {ε : ℝ≥0} (hε : 0 < ε) : + ∃ s, μ s = 0 ∧ ν sᶜ ≤ 2 * ε := by + have h₁ : (μ ⊓ ν) univ = 0 := le_bot_iff.1 (h (inf_le_left (b := ν)) inf_le_right) ▸ rfl + simp_rw [Measure.inf_apply MeasurableSet.univ, inter_univ] at h₁ + have h₂ : ∀ n : ℕ, ∃ t, μ t + ν tᶜ < ε * (1 / 2) ^ n := by + intro n + obtain ⟨m, ⟨t, ht₁, rfl⟩, hm₂⟩ : + ∃ x ∈ {m | ∃ t, m = μ t + ν tᶜ}, x < ε * (1 / 2 : ℝ≥0∞) ^ n := by + refine exists_lt_of_csInf_lt ⟨ν univ, ∅, by simp⟩ <| h₁ ▸ ENNReal.mul_pos ?_ (by simp) + norm_cast + exact hε.ne.symm + exact ⟨t, hm₂⟩ + choose t ht₂ using h₂ + refine ⟨⋂ n, t n, ?_, ?_⟩ + · refine eq_zero_of_le_mul_pow (by norm_num) + fun n ↦ ((measure_mono <| iInter_subset_of_subset n fun _ ht ↦ ht).trans + (le_add_right le_rfl)).trans (ht₂ n).le + · rw [compl_iInter, (by simp [ENNReal.tsum_mul_left, mul_comm] : + 2 * (ε : ℝ≥0∞) = ∑' (n : ℕ), ε * (1 / 2 : ℝ≥0∞) ^ n)] + refine (measure_iUnion_le _).trans ?_ + exact tsum_le_tsum (fun n ↦ (le_add_left le_rfl).trans (ht₂ n).le) + ENNReal.summable ENNReal.summable + +lemma mutuallySingular_of_disjoint (h : Disjoint μ ν) : μ ⟂ₘ ν := by + have h' (n : ℕ) : ∃ s, μ s = 0 ∧ ν sᶜ ≤ (1 / 2) ^ n := by + convert exists_null_set_measure_lt_of_disjoint h (ε := (1 / 2) ^ (n + 1)) + <| pow_pos (by simp) (n + 1) + push_cast + rw [pow_succ, ← mul_assoc, mul_comm, ← mul_assoc] + norm_cast + rw [div_mul_cancel₀, one_mul] + · push_cast + simp + · simp + choose s hs₂ hs₃ using h' + refine Measure.MutuallySingular.mk (t := (⋃ n, s n)ᶜ) (measure_iUnion_null hs₂) ?_ ?_ + · rw [compl_iUnion] + refine eq_zero_of_le_mul_pow (ε := 1) (by norm_num : (1 / 2 : ℝ≥0∞) < 1) <| fun n ↦ ?_ + rw [ENNReal.coe_one, one_mul] + exact (measure_mono <| iInter_subset_of_subset n fun _ ht ↦ ht).trans (hs₃ n) + · rw [union_compl_self] + +lemma MutuallySingular.disjoint (h : μ ⟂ₘ ν) : Disjoint μ ν := by + have h_bot_iff (ξ : Measure α) : ξ ≤ ⊥ ↔ ξ = 0 := by + rw [le_bot_iff] + rfl + intro ξ hξμ hξν + rw [h_bot_iff] + ext s hs + simp only [Measure.coe_zero, Pi.zero_apply] + rw [← inter_union_compl s h.nullSet, measure_union, add_eq_zero] + · exact ⟨measure_inter_null_of_null_right _ <| absolutelyContinuous_of_le hξμ h.measure_nullSet, + measure_inter_null_of_null_right _ <| absolutelyContinuous_of_le hξν h.measure_compl_nullSet⟩ + · exact Disjoint.mono inter_subset_right inter_subset_right disjoint_compl_right + · exact hs.inter h.measurableSet_nullSet.compl + +lemma MutuallySingular.disjoint_ae (h : μ ⟂ₘ ν) : Disjoint (ae μ) (ae ν) := by + rw [disjoint_iff_inf_le] + intro s _ + refine ⟨s ∪ h.nullSetᶜ, ?_, s ∪ h.nullSet, ?_, ?_⟩ + · rw [mem_ae_iff, compl_union, compl_compl] + exact measure_inter_null_of_null_right _ h.measure_nullSet + · rw [mem_ae_iff, compl_union] + exact measure_inter_null_of_null_right _ h.measure_compl_nullSet + · rw [union_eq_compl_compl_inter_compl, union_eq_compl_compl_inter_compl, + ← compl_union, compl_compl, inter_union_compl, compl_compl] + +lemma disjoint_of_disjoint_ae (h : Disjoint (ae μ) (ae ν)) : Disjoint μ ν := by + rw [disjoint_iff_inf_le] at h ⊢ + refine Measure.le_intro fun s hs _ ↦ ?_ + rw [Measure.inf_apply hs] + have : (⊥ : Measure α) = 0 := rfl + simp only [this, Measure.coe_zero, Pi.zero_apply, nonpos_iff_eq_zero] + specialize h (mem_bot (s := sᶜ)) + rw [mem_inf_iff] at h + obtain ⟨t₁, ht₁, t₂, ht₂, h_eq'⟩ := h + have h_eq : s = t₁ᶜ ∪ t₂ᶜ := by + rw [union_eq_compl_compl_inter_compl, compl_compl, compl_compl, ← h_eq', compl_compl] + rw [mem_ae_iff] at ht₁ ht₂ + refine le_antisymm ?_ zero_le' + refine sInf_le_of_le (a := 0) (b := 0) ?_ le_rfl + rw [h_eq] + refine ⟨t₁ᶜ ∩ t₂, Eq.symm ?_⟩ + rw [add_eq_zero] + constructor + · refine measure_inter_null_of_null_left _ ?_ + exact measure_inter_null_of_null_left _ ht₁ + · rw [compl_inter, compl_compl, union_eq_compl_compl_inter_compl, + union_eq_compl_compl_inter_compl, ← compl_union, compl_compl, compl_compl, inter_comm, + inter_comm t₁, union_comm, inter_union_compl] + exact ht₂ + +lemma mutuallySingular_tfae : List.TFAE + [ μ ⟂ₘ ν, + Disjoint μ ν, + Disjoint (ae μ) (ae ν) ] := by + tfae_have 1 → 2 + | h => h.disjoint + tfae_have 2 → 1 + | h => mutuallySingular_of_disjoint h + tfae_have 1 → 3 + | h => h.disjoint_ae + tfae_have 3 → 2 + | h => disjoint_of_disjoint_ae h + tfae_finish + +lemma mutuallySingular_iff_disjoint : μ ⟂ₘ ν ↔ Disjoint μ ν := + mutuallySingular_tfae.out 0 1 + +lemma mutuallySingular_iff_disjoint_ae : μ ⟂ₘ ν ↔ Disjoint (ae μ) (ae ν) := + mutuallySingular_tfae.out 0 2 + end Measure end MeasureTheory diff --git a/Mathlib/MeasureTheory/Measure/Prod.lean b/Mathlib/MeasureTheory/Measure/Prod.lean index 4a67f092f79cf..b1b1cf0cd1ea5 100644 --- a/Mathlib/MeasureTheory/Measure/Prod.lean +++ b/Mathlib/MeasureTheory/Measure/Prod.lean @@ -194,7 +194,7 @@ theorem prod_prod (s : Set α) (t : Set β) : μ.prod ν (s ×ˢ t) = μ s * ν μ.prod ν (s ×ˢ t) ≤ μ.prod ν (S ×ˢ T) := by gcongr <;> apply subset_toMeasurable _ = μ S * ν T := by rw [prod_apply hSTm] - simp_rw [mk_preimage_prod_right_eq_if, measure_if, + simp_rw [S, mk_preimage_prod_right_eq_if, measure_if, lintegral_indicator (measurableSet_toMeasurable _ _), lintegral_const, restrict_apply_univ, mul_comm] _ = μ s * ν t := by rw [measure_toMeasurable, measure_toMeasurable] diff --git a/Mathlib/MeasureTheory/Measure/Stieltjes.lean b/Mathlib/MeasureTheory/Measure/Stieltjes.lean index 262bd709454e1..a381f2f16d3fb 100644 --- a/Mathlib/MeasureTheory/Measure/Stieltjes.lean +++ b/Mathlib/MeasureTheory/Measure/Stieltjes.lean @@ -129,6 +129,8 @@ instance : Module ℝ≥0 StieltjesFunction where add_smul _ _ _ := ext fun _ ↦ add_mul _ _ _ zero_smul _ := ext fun _ ↦ zero_mul _ +@[simp] lemma zero_apply (x : ℝ) : (0 : StieltjesFunction) x = 0 := rfl + @[simp] lemma add_apply (f g : StieltjesFunction) (x : ℝ) : (f + g) x = f x + g x := rfl /-- If a function `f : ℝ → ℝ` is monotone, then the function mapping `x` to the right limit of `f` @@ -430,6 +432,12 @@ theorem measure_Iic {l : ℝ} (hf : Tendsto f atBot (𝓝 l)) (x : ℝ) : simp_rw [measure_Ioc] exact ENNReal.tendsto_ofReal (Tendsto.const_sub _ hf) +lemma measure_Iio {l : ℝ} (hf : Tendsto f atBot (𝓝 l)) (x : ℝ) : + f.measure (Iio x) = ofReal (leftLim f x - l) := by + rw [← Iic_diff_right, measure_diff _ (nullMeasurableSet_singleton x), measure_singleton, + f.measure_Iic hf, ← ofReal_sub _ (sub_nonneg.mpr <| Monotone.leftLim_le f.mono' le_rfl)] + <;> simp + theorem measure_Ici {l : ℝ} (hf : Tendsto f atTop (𝓝 l)) (x : ℝ) : f.measure (Ici x) = ofReal (l - leftLim f x) := by refine tendsto_nhds_unique (tendsto_measure_Ico_atTop _ _) ?_ @@ -441,12 +449,52 @@ theorem measure_Ici {l : ℝ} (hf : Tendsto f atTop (𝓝 l)) (x : ℝ) : rw [tendsto_atTop_atTop] exact fun y => ⟨y + 1, fun z hyz => by rwa [le_sub_iff_add_le]⟩ +lemma measure_Ioi {l : ℝ} (hf : Tendsto f atTop (𝓝 l)) (x : ℝ) : + f.measure (Ioi x) = ofReal (l - f x) := by + rw [← Ici_diff_left, measure_diff _ (nullMeasurableSet_singleton x), measure_singleton, + f.measure_Ici hf, ← ofReal_sub _ (sub_nonneg.mpr <| Monotone.leftLim_le f.mono' le_rfl)] + <;> simp + +lemma measure_Ioi_of_tendsto_atTop_atTop (hf : Tendsto f atTop atTop) (x : ℝ) : + f.measure (Ioi x) = ∞ := by + refine ENNReal.eq_top_of_forall_nnreal_le fun r ↦ ?_ + obtain ⟨N, hN⟩ := eventually_atTop.mp (tendsto_atTop.mp hf (r + f x)) + exact (f.measure_Ioc x (max x N) ▸ ENNReal.coe_nnreal_eq r ▸ (ENNReal.ofReal_le_ofReal <| + le_tsub_of_add_le_right <| hN _ (le_max_right x N))).trans (measure_mono Ioc_subset_Ioi_self) + +lemma measure_Ici_of_tendsto_atTop_atTop (hf : Tendsto f atTop atTop) (x : ℝ) : + f.measure (Ici x) = ∞ := by + rw [← top_le_iff, ← f.measure_Ioi_of_tendsto_atTop_atTop hf x] + exact measure_mono Ioi_subset_Ici_self + +lemma measure_Iic_of_tendsto_atBot_atBot (hf : Tendsto f atBot atBot) (x : ℝ) : + f.measure (Iic x) = ∞ := by + refine ENNReal.eq_top_of_forall_nnreal_le fun r ↦ ?_ + obtain ⟨N, hN⟩ := eventually_atBot.mp (tendsto_atBot.mp hf (f x - r)) + exact (f.measure_Ioc (min x N) x ▸ ENNReal.coe_nnreal_eq r ▸ (ENNReal.ofReal_le_ofReal <| + le_sub_comm.mp <| hN _ (min_le_right x N))).trans (measure_mono Ioc_subset_Iic_self) + +lemma measure_Iio_of_tendsto_atBot_atBot (hf : Tendsto f atBot atBot) (x : ℝ) : + f.measure (Iio x) = ∞ := by + rw [← top_le_iff, ← f.measure_Iic_of_tendsto_atBot_atBot hf (x - 1)] + exact measure_mono <| Set.Iic_subset_Iio.mpr <| sub_one_lt x + theorem measure_univ {l u : ℝ} (hfl : Tendsto f atBot (𝓝 l)) (hfu : Tendsto f atTop (𝓝 u)) : f.measure univ = ofReal (u - l) := by refine tendsto_nhds_unique (tendsto_measure_Iic_atTop _) ?_ simp_rw [measure_Iic f hfl] exact ENNReal.tendsto_ofReal (Tendsto.sub_const hfu _) +lemma measure_univ_of_tendsto_atTop_atTop (hf : Tendsto f atTop atTop) : + f.measure univ = ∞ := by + rw [← top_le_iff, ← f.measure_Ioi_of_tendsto_atTop_atTop hf 0] + exact measure_mono (subset_univ _) + +lemma measure_univ_of_tendsto_atBot_atBot (hf : Tendsto f atBot atBot) : + f.measure univ = ∞ := by + rw [← top_le_iff, ← f.measure_Iio_of_tendsto_atBot_atBot hf 0] + exact measure_mono (subset_univ _) + lemma isFiniteMeasure {l u : ℝ} (hfl : Tendsto f atBot (𝓝 l)) (hfu : Tendsto f atTop (𝓝 u)) : IsFiniteMeasure f.measure := ⟨by simp [f.measure_univ hfl hfu]⟩ @@ -490,9 +538,13 @@ lemma eq_of_measure_of_eq (g : StieltjesFunction) {y : ℝ} · rw [sub_nonneg] exact f.mono hxy +@[simp] +lemma measure_zero : StieltjesFunction.measure 0 = 0 := + Measure.ext_of_Ioc _ _ (by simp) + @[simp] lemma measure_const (c : ℝ) : (StieltjesFunction.const c).measure = 0 := - Measure.ext_of_Ioc _ _ (fun _ _ _ ↦ by simp) + Measure.ext_of_Ioc _ _ (by simp) @[simp] lemma measure_add (f g : StieltjesFunction) : (f + g).measure = f.measure + g.measure := by diff --git a/Mathlib/MeasureTheory/Measure/WithDensity.lean b/Mathlib/MeasureTheory/Measure/WithDensity.lean index f8c9285e8bbbf..f2b8b222f5c26 100644 --- a/Mathlib/MeasureTheory/Measure/WithDensity.lean +++ b/Mathlib/MeasureTheory/Measure/WithDensity.lean @@ -385,7 +385,7 @@ theorem lintegral_withDensity_eq_lintegral_mul₀' {μ : Measure α} {f : α → rw [EventuallyEq, ae_withDensity_iff_ae_restrict hf.measurable_mk] at Z filter_upwards [Z] intro x hx - simp only [hx, Pi.mul_apply] + simp only [g', hx, Pi.mul_apply] · have M : MeasurableSet { x : α | f' x ≠ 0 }ᶜ := (hf.measurable_mk (measurableSet_singleton 0).compl).compl filter_upwards [ae_restrict_mem M] @@ -396,7 +396,7 @@ theorem lintegral_withDensity_eq_lintegral_mul₀' {μ : Measure α} {f : α → apply lintegral_congr_ae filter_upwards [hf.ae_eq_mk] intro x hx - simp only [hx, Pi.mul_apply] + simp only [f', hx, Pi.mul_apply] lemma setLIntegral_withDensity_eq_lintegral_mul₀' {μ : Measure α} {f : α → ℝ≥0∞} (hf : AEMeasurable f μ) {g : α → ℝ≥0∞} (hg : AEMeasurable g (μ.withDensity f)) @@ -483,7 +483,7 @@ theorem lintegral_withDensity_eq_lintegral_mul_non_measurable₀ (μ : Measure apply lintegral_congr_ae filter_upwards [hf.ae_eq_mk] intro x hx - simp only [hx, Pi.mul_apply] + simp only [f', hx, Pi.mul_apply] theorem setLIntegral_withDensity_eq_setLIntegral_mul_non_measurable₀ (μ : Measure α) {f : α → ℝ≥0∞} {s : Set α} (hf : AEMeasurable f (μ.restrict s)) (g : α → ℝ≥0∞) diff --git a/Mathlib/MeasureTheory/OuterMeasure/Basic.lean b/Mathlib/MeasureTheory/OuterMeasure/Basic.lean index 42207c8540857..24180bd2709cb 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/Basic.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/Basic.lean @@ -61,7 +61,7 @@ theorem measure_iUnion_le [Countable ι] (s : ι → Set α) : μ (⋃ i, s i) μ (⋃ i, t i) = μ (⋃ i, disjointed t i) := by rw [iUnion_disjointed] _ ≤ ∑' i, μ (disjointed t i) := OuterMeasureClass.measure_iUnion_nat_le _ _ (disjoint_disjointed _) - _ ≤ ∑' i, μ (t i) := by gcongr; apply disjointed_subset + _ ≤ ∑' i, μ (t i) := by gcongr; exact disjointed_subset .. theorem measure_biUnion_le {I : Set ι} (μ : F) (hI : I.Countable) (s : ι → Set α) : μ (⋃ i ∈ I, s i) ≤ ∑' i : I, μ (s i) := by diff --git a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean index ac7e4d2a1aaca..116867bde48c2 100644 --- a/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean +++ b/Mathlib/MeasureTheory/OuterMeasure/OfFunction.lean @@ -124,7 +124,7 @@ theorem ofFunction_le (s : Set α) : OuterMeasure.ofFunction m m_empty s ≤ m s le_of_eq <| tsum_eq_single 0 <| by rintro (_ | i) · simp - · simp [m_empty] + · simp [f, m_empty] theorem ofFunction_eq (s : Set α) (m_mono : ∀ ⦃t : Set α⦄, s ⊆ t → m s ≤ m t) (m_subadd : ∀ s : ℕ → Set α, m (⋃ i, s i) ≤ ∑' i, m (s i)) : diff --git a/Mathlib/MeasureTheory/VectorMeasure/Basic.lean b/Mathlib/MeasureTheory/VectorMeasure/Basic.lean index e5e7a7d55a5d6..c316fb186a98b 100644 --- a/Mathlib/MeasureTheory/VectorMeasure/Basic.lean +++ b/Mathlib/MeasureTheory/VectorMeasure/Basic.lean @@ -710,9 +710,8 @@ theorem le_iff' : v ≤ w ↔ ∀ i, v i ≤ w i := by end -set_option quotPrecheck false in -- Porting note: error message suggested to do this scoped[MeasureTheory] - notation:50 v " ≤[" i:50 "] " w:50 => + notation3:50 v " ≤[" i:50 "] " w:50 => MeasureTheory.VectorMeasure.restrict v i ≤ MeasureTheory.VectorMeasure.restrict w i section diff --git a/Mathlib/ModelTheory/Encoding.lean b/Mathlib/ModelTheory/Encoding.lean index e3832e469136b..859366d1da80f 100644 --- a/Mathlib/ModelTheory/Encoding.lean +++ b/Mathlib/ModelTheory/Encoding.lean @@ -234,7 +234,7 @@ theorem listDecode_encode_list (l : List (Σn, L.BoundedFormula α n)) : Σn, L.Term (α ⊕ (Fin n)))) (finRange φ_l) ++ l)).get? ↑i).join = some ⟨_, ts i⟩ := by intro i simp only [Option.join, map_append, map_map, Option.bind_eq_some, id, exists_eq_right, - get?_eq_some, length_append, length_map, length_finRange] + get?_eq_some_iff, length_append, length_map, length_finRange] refine ⟨lt_of_lt_of_le i.2 le_self_add, ?_⟩ rw [get_eq_getElem, getElem_append_left, getElem_map] · simp only [getElem_finRange, cast_mk, Fin.eta, Function.comp_apply, Sum.getLeft?_inl] diff --git a/Mathlib/ModelTheory/Fraisse.lean b/Mathlib/ModelTheory/Fraisse.lean index ce7356ee4aeb5..f782029a8eaa0 100644 --- a/Mathlib/ModelTheory/Fraisse.lean +++ b/Mathlib/ModelTheory/Fraisse.lean @@ -29,8 +29,8 @@ Fraïssé limit - the countable ultrahomogeneous structure with that age. - A class `K` has `FirstOrder.Language.Amalgamation` when for any pair of embeddings of a structure `M` in `K` into other structures in `K`, those two structures can be embedded into a fourth structure in `K` such that the resulting square of embeddings commutes. -- `FirstOrder.Language.IsFraisse` indicates that a class is nonempty, isomorphism-invariant, - essentially countable, and satisfies the hereditary, joint embedding, and amalgamation properties. +- `FirstOrder.Language.IsFraisse` indicates that a class is nonempty, essentially countable, + and satisfies the hereditary, joint embedding, and amalgamation properties. - `FirstOrder.Language.IsFraisseLimit` indicates that a structure is a Fraïssé limit for a given class. @@ -109,12 +109,11 @@ def Amalgamation : Prop := M ∈ K → N ∈ K → P ∈ K → ∃ (Q : Bundled.{w} L.Structure) (NQ : N ↪[L] Q) (PQ : P ↪[L] Q), Q ∈ K ∧ NQ.comp MN = PQ.comp MP -/-- A Fraïssé class is a nonempty, isomorphism-invariant, essentially countable class of structures -satisfying the hereditary, joint embedding, and amalgamation properties. -/ +/-- A Fraïssé class is a nonempty, essentially countable class of structures satisfying the +hereditary, joint embedding, and amalgamation properties. -/ class IsFraisse : Prop where is_nonempty : K.Nonempty FG : ∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M - is_equiv_invariant : ∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K) is_essentially_countable : (Quotient.mk' '' K).Countable hereditary : Hereditary K jointEmbedding : JointEmbedding K @@ -146,6 +145,10 @@ theorem Hereditary.is_equiv_invariant_of_fg (h : Hereditary K) ⟨fun MK => h M MK ((fg M MK).mem_age_of_equiv hn), fun NK => h N NK ((fg N NK).mem_age_of_equiv ⟨hn.some.symm⟩)⟩ +theorem IsFraisse.is_equiv_invariant [h : IsFraisse K] {M N : Bundled.{w} L.Structure} + (hn : Nonempty (M ≃[L] N)) : M ∈ K ↔ N ∈ K := + h.hereditary.is_equiv_invariant_of_fg h.FG M N hn + variable (M) theorem age.nonempty : (L.age M).Nonempty := @@ -221,7 +224,6 @@ theorem age_directLimit {ι : Type w} [Preorder ι] [IsDirected ι (· ≤ ·)] /-- Sufficient conditions for a class to be the age of a countably-generated structure. -/ theorem exists_cg_is_age_of (hn : K.Nonempty) - (h : ∀ M N : Bundled.{w} L.Structure, Nonempty (M ≃[L] N) → (M ∈ K ↔ N ∈ K)) (hc : (Quotient.mk' '' K).Countable) (fg : ∀ M : Bundled.{w} L.Structure, M ∈ K → Structure.FG L M) (hp : Hereditary K) (jep : JointEmbedding K) : ∃ M : Bundled.{w} L.Structure, Structure.CG L M ∧ L.age M = K := by @@ -234,7 +236,7 @@ theorem exists_cg_is_age_of (hn : K.Nonempty) -- Porting note: fix hP2 because `Quotient.out (Quotient.mk' x) ≈ a` was not simplified -- to `x ≈ a` in hF replace hP2 := Setoid.trans (Setoid.symm (Quotient.mk_out P)) hP2 - exact (h _ _ hP2).1 hP1 + exact (hp.is_equiv_invariant_of_fg fg _ _ hP2).1 hP1 choose P hPK hP hFP using fun (N : K) (n : ℕ) => jep N N.2 (F (n + 1)).out (hF' _) let G : ℕ → K := @Nat.rec (fun _ => K) ⟨(F 0).out, hF' 0⟩ fun n N => ⟨P N n, hPK N n⟩ -- Poting note: was @@ -265,8 +267,8 @@ theorem exists_countable_is_age_of_iff [Countable (Σ l, L.Functions l)] : · rintro ⟨M, h1, h2, rfl⟩ refine ⟨age.nonempty M, age.is_equiv_invariant L M, age.countable_quotient M, fun N hN => hN.1, age.hereditary M, age.jointEmbedding M⟩ - · rintro ⟨Kn, eqinv, cq, hfg, hp, jep⟩ - obtain ⟨M, hM, rfl⟩ := exists_cg_is_age_of Kn eqinv cq hfg hp jep + · rintro ⟨Kn, _, cq, hfg, hp, jep⟩ + obtain ⟨M, hM, rfl⟩ := exists_cg_is_age_of Kn cq hfg hp jep exact ⟨M, Structure.cg_iff_countable.1 hM, rfl⟩ variable (L) @@ -358,7 +360,7 @@ theorem IsUltrahomogeneous.amalgamation_age (h : L.IsUltrahomogeneous M) : theorem IsUltrahomogeneous.age_isFraisse [Countable M] (h : L.IsUltrahomogeneous M) : IsFraisse (L.age M) := - ⟨age.nonempty M, fun _ hN => hN.1, age.is_equiv_invariant L M, age.countable_quotient M, + ⟨age.nonempty M, fun _ hN => hN.1, age.countable_quotient M, age.hereditary M, age.jointEmbedding M, h.amalgamation_age⟩ namespace IsFraisseLimit @@ -387,7 +389,7 @@ protected theorem isExtensionPair : L.IsExtensionPair M N := by refine ⟨⟨⟨S, g.toHom.range, g.equivRange⟩, S_FG⟩, subset_closure.trans (le_sup_right : _ ≤ S) (mem_singleton m), ⟨le_sup_left, ?_⟩⟩ ext - simp [Subtype.mk_le_mk, PartialEquiv.le_def, g_eq] + simp [S, Subtype.mk_le_mk, PartialEquiv.le_def, g_eq] /-- The Fraïssé limit of a class is unique, in that any two Fraïssé limits are isomorphic. -/ theorem nonempty_equiv : Nonempty (M ≃[L] N) := by diff --git a/Mathlib/ModelTheory/PartialEquiv.lean b/Mathlib/ModelTheory/PartialEquiv.lean index 52f75fe5211e9..6a0442f49b37a 100644 --- a/Mathlib/ModelTheory/PartialEquiv.lean +++ b/Mathlib/ModelTheory/PartialEquiv.lean @@ -451,13 +451,13 @@ protected alias ⟨cod, _⟩ := isExtensionPair_iff_cod def definedAtLeft (h : L.IsExtensionPair M N) (m : M) : Order.Cofinal (FGEquiv L M N) where carrier := {f | m ∈ f.val.dom} - mem_gt := fun f => h f m + isCofinal := fun f => h f m /-- The cofinal set of finite equivalences with a given element in their codomain. -/ def definedAtRight (h : L.IsExtensionPair N M) (n : N) : Order.Cofinal (FGEquiv L M N) where carrier := {f | n ∈ f.val.cod} - mem_gt := fun f => h.cod f n + isCofinal := fun f => h.cod f n end IsExtensionPair diff --git a/Mathlib/ModelTheory/Substructures.lean b/Mathlib/ModelTheory/Substructures.lean index d5f9680e0bee2..a3b0c3233492f 100644 --- a/Mathlib/ModelTheory/Substructures.lean +++ b/Mathlib/ModelTheory/Substructures.lean @@ -251,6 +251,7 @@ theorem closure_le : closure L s ≤ S ↔ s ⊆ S := /-- Substructure closure of a set is monotone in its argument: if `s ⊆ t`, then `closure L s ≤ closure L t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set M⦄ (h : s ⊆ t) : closure L s ≤ closure L t := (closure L).monotone h diff --git a/Mathlib/ModelTheory/Syntax.lean b/Mathlib/ModelTheory/Syntax.lean index 14e6d78b779dd..ff03d55615d75 100644 --- a/Mathlib/ModelTheory/Syntax.lean +++ b/Mathlib/ModelTheory/Syntax.lean @@ -6,6 +6,7 @@ Authors: Aaron Anderson, Jesse Michael Han, Floris van Doorn import Mathlib.Data.Set.Prod import Mathlib.Logic.Equiv.Fin import Mathlib.ModelTheory.LanguageMap +import Mathlib.Algebra.Order.Ring.Nat /-! # Basics on First-Order Syntax diff --git a/Mathlib/NumberTheory/AbelSummation.lean b/Mathlib/NumberTheory/AbelSummation.lean new file mode 100644 index 0000000000000..69dc93ce98099 --- /dev/null +++ b/Mathlib/NumberTheory/AbelSummation.lean @@ -0,0 +1,173 @@ +/- +Copyright (c) 2024 Xavier Roblot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Xavier Roblot +-/ +import Mathlib.MeasureTheory.Integral.FundThmCalculus + +/-! +# Abel's summation formula + +We prove several versions of Abel's summation formula. + +## Results + +* `sum_mul_eq_sub_sub_integral_mul`: general statement of the formula for a sum between two +(nonnegative) reals `a` and `b`. + +* `sum_mul_eq_sub_integral_mul`: a specialized version of `sum_mul_eq_sub_sub_integral_mul` for + the case `a = 0`. + + * `sum_mul_eq_sub_integral_mul`: a specialized version of `sum_mul_eq_sub_integral_mul` for + when the first coefficient of the sequence is `0`. This is useful for `ArithmeticFunction`. + +## References + +* + +-/ + +noncomputable section + +open Finset intervalIntegral MeasureTheory IntervalIntegrable + +variable {𝕜 : Type*} [RCLike 𝕜] (c : ℕ → 𝕜) {f : ℝ → 𝕜} {a b : ℝ} + +namespace abelSummationProof + +private theorem sumlocc (n : ℕ) : + ∀ᵐ t, t ∈ Set.Icc (n : ℝ) (n + 1) → ∑ k ∈ Icc 0 ⌊t⌋₊, c k = ∑ k ∈ Icc 0 n, c k := by + filter_upwards [Ico_ae_eq_Icc] with t h ht + rw [Nat.floor_eq_on_Ico _ _ (h.mpr ht)] + +private theorem integralmulsum (hf_diff : ∀ t ∈ Set.Icc a b, DifferentiableAt ℝ f t) + (hf_int : IntegrableOn (deriv f) (Set.Icc a b)) (t₁ t₂ : ℝ) (n : ℕ) (h : t₁ ≤ t₂) + (h₁ : n ≤ t₁) (h₂ : t₂ ≤ n + 1) (h₃ : a ≤ t₁) (h₄ : t₂ ≤ b) : + ∫ t in t₁..t₂, deriv f t * ∑ k ∈ Icc 0 ⌊t⌋₊, c k = + (f t₂ - f t₁) * ∑ k ∈ Icc 0 n, c k := by + have h_inc₁ : Ι t₁ t₂ ⊆ Set.Icc n (n + 1) := + Set.uIoc_of_le h ▸ Set.Ioc_subset_Icc_self.trans <| Set.Icc_subset_Icc h₁ h₂ + have h_inc₂ : Set.uIcc t₁ t₂ ⊆ Set.Icc a b := Set.uIcc_of_le h ▸ Set.Icc_subset_Icc h₃ h₄ + rw [← integral_deriv_eq_sub (fun t ht ↦ hf_diff t (h_inc₂ ht)), ← integral_mul_const] + · refine integral_congr_ae ?_ + filter_upwards [sumlocc c n] with t h h' + rw [h (h_inc₁ h')] + · refine (intervalIntegrable_iff_integrableOn_Icc_of_le h).mpr (hf_int.mono_set ?_) + rwa [← Set.uIcc_of_le h] + +private theorem ineqofmemIco {k : ℕ} (hk : k ∈ Set.Ico (⌊a⌋₊ + 1) ⌊b⌋₊) : + a ≤ k ∧ k + 1 ≤ b := by + constructor + · have := (Set.mem_Ico.mp hk).1 + exact le_of_lt <| (Nat.floor_lt' (by omega)).mp this + · rw [← Nat.cast_add_one, ← Nat.le_floor_iff' (Nat.succ_ne_zero k)] + exact (Set.mem_Ico.mp hk).2 + +private theorem ineqofmemIco' {k : ℕ} (hk : k ∈ Ico (⌊a⌋₊ + 1) ⌊b⌋₊) : + a ≤ k ∧ k + 1 ≤ b := + ineqofmemIco (by rwa [← Finset.coe_Ico]) + +private theorem integrablemulsum (ha : 0 ≤ a) (hb : ⌊a⌋₊ < ⌊b⌋₊) + (hf_int : IntegrableOn (deriv f) (Set.Icc a b)) : + IntegrableOn (fun t ↦ deriv f t * (∑ k ∈ Icc 0 ⌊t⌋₊, c k)) (Set.Icc a b) := by + have h_locint {t₁ t₂ : ℝ} {n : ℕ} (h : t₁ ≤ t₂) (h₁ : n ≤ t₁) (h₂ : t₂ ≤ n + 1) + (h₃ : a ≤ t₁) (h₄ : t₂ ≤ b) : + IntervalIntegrable (fun t ↦ deriv f t * (∑ k ∈ Icc 0 ⌊t⌋₊, c k)) volume t₁ t₂ := by + rw [intervalIntegrable_iff_integrableOn_Icc_of_le h] + exact (IntegrableOn.mono_set (hf_int.mul_const _) (Set.Icc_subset_Icc h₃ h₄)).congr + <| ae_restrict_of_ae_restrict_of_subset (Set.Icc_subset_Icc h₁ h₂) + <| (ae_restrict_iff' measurableSet_Icc).mpr + (by filter_upwards [sumlocc c n] with t h ht using by rw [h ht]) + have aux1 : 0 ≤ b := (Nat.pos_of_floor_pos <| (Nat.zero_le _).trans_lt hb).le + have aux2 : ⌊a⌋₊ + 1 ≤ b := by rwa [← Nat.cast_add_one, ← Nat.le_floor_iff aux1] + have aux3 : a ≤ ⌊a⌋₊ + 1 := (Nat.lt_floor_add_one _).le + have aux4 : a ≤ ⌊b⌋₊ := le_of_lt (by rwa [← Nat.floor_lt ha]) + -- now break up into 3 subintervals + rw [← intervalIntegrable_iff_integrableOn_Icc_of_le (aux3.trans aux2)] + have I1 : IntervalIntegrable _ volume a ↑(⌊a⌋₊ + 1) := + h_locint (mod_cast aux3) (Nat.floor_le ha) (mod_cast le_rfl) le_rfl (mod_cast aux2) + have I2 : IntervalIntegrable _ volume ↑(⌊a⌋₊ + 1) ⌊b⌋₊ := + trans_iterate_Ico hb fun k hk ↦ h_locint (mod_cast k.le_succ) + le_rfl (mod_cast le_rfl) (ineqofmemIco hk).1 (mod_cast (ineqofmemIco hk).2) + have I3 : IntervalIntegrable _ volume ⌊b⌋₊ b := + h_locint (Nat.floor_le aux1) le_rfl (Nat.lt_floor_add_one _).le aux4 le_rfl + exact (I1.trans I2).trans I3 + +/-- Abel's summation formula. -/ +theorem _root_.sum_mul_eq_sub_sub_integral_mul (ha : 0 ≤ a) (hab : a ≤ b) + (hf_diff : ∀ t ∈ Set.Icc a b, DifferentiableAt ℝ f t) + (hf_int : IntegrableOn (deriv f) (Set.Icc a b)) : + ∑ k ∈ Ioc ⌊a⌋₊ ⌊b⌋₊, f k * c k = + f b * (∑ k ∈ Icc 0 ⌊b⌋₊, c k) - f a * (∑ k ∈ Icc 0 ⌊a⌋₊, c k) - + ∫ t in Set.Ioc a b, deriv f t * (∑ k ∈ Icc 0 ⌊t⌋₊, c k) := by + rw [← integral_of_le hab] + have aux1 : ⌊a⌋₊ ≤ a := Nat.floor_le ha + have aux2 : b ≤ ⌊b⌋₊ + 1 := (Nat.lt_floor_add_one _).le + -- We consider two cases depending on whether the sum is empty or not + obtain hb | hb := eq_or_lt_of_le (Nat.floor_le_floor hab) + · rw [hb, Ioc_eq_empty_of_le le_rfl, sum_empty, ← sub_mul, + integralmulsum c hf_diff hf_int _ _ ⌊b⌋₊ hab (hb ▸ aux1) aux2 le_rfl le_rfl, sub_self] + have aux3 : a ≤ ⌊a⌋₊ + 1 := (Nat.lt_floor_add_one _).le + have aux4 : ⌊a⌋₊ + 1 ≤ b := by rwa [← Nat.cast_add_one, ← Nat.le_floor_iff (ha.trans hab)] + have aux5 : ⌊b⌋₊ ≤ b := Nat.floor_le (ha.trans hab) + have aux6 : a ≤ ⌊b⌋₊ := Nat.floor_lt ha |>.mp hb |>.le + simp_rw [← smul_eq_mul, sum_Ioc_by_parts (fun k ↦ f k) _ hb, range_eq_Ico, Nat.Ico_succ_right, + smul_eq_mul] + have : ∑ k ∈ Ioc ⌊a⌋₊ (⌊b⌋₊ - 1), (f ↑(k + 1) - f k) * ∑ n ∈ Icc 0 k, c n = + ∑ k ∈ Ico (⌊a⌋₊ + 1) ⌊b⌋₊, ∫ t in k..↑(k + 1), deriv f t * ∑ n ∈ Icc 0 ⌊t⌋₊, c n := by + rw [← Nat.Ico_succ_succ, Nat.succ_eq_add_one, Nat.succ_eq_add_one, Nat.sub_add_cancel + (by omega), Eq.comm] + exact sum_congr rfl fun k hk ↦ (integralmulsum c hf_diff hf_int _ _ _ (mod_cast k.le_succ) + le_rfl (mod_cast le_rfl) (ineqofmemIco' hk).1 <| mod_cast (ineqofmemIco' hk).2) + rw [this, sum_integral_adjacent_intervals_Ico hb, Nat.cast_add, Nat.cast_one, + ← integral_interval_sub_left (a := a) (c := ⌊a⌋₊ + 1), + ← integral_add_adjacent_intervals (b := ⌊b⌋₊) (c := b), + integralmulsum c hf_diff hf_int _ _ _ aux3 aux1 le_rfl le_rfl aux4, + integralmulsum c hf_diff hf_int _ _ _ aux5 le_rfl aux2 aux6 le_rfl] + · ring + -- now deal with the integrability side goals + -- (Note we have 5 goals, but the 1st and 3rd are identical. TODO: find a non-hacky way of dealing + -- with both at once.) + · rw [intervalIntegrable_iff_integrableOn_Icc_of_le aux6] + exact (integrablemulsum c ha hb hf_int).mono_set (Set.Icc_subset_Icc_right aux5) + · rw [intervalIntegrable_iff_integrableOn_Icc_of_le aux5] + exact (integrablemulsum c ha hb hf_int).mono_set (Set.Icc_subset_Icc_left aux6) + · rw [intervalIntegrable_iff_integrableOn_Icc_of_le aux6] + exact (integrablemulsum c ha hb hf_int).mono_set (Set.Icc_subset_Icc_right aux5) + · rw [intervalIntegrable_iff_integrableOn_Icc_of_le aux3] + exact (integrablemulsum c ha hb hf_int).mono_set (Set.Icc_subset_Icc_right aux4) + · exact fun k hk ↦ (intervalIntegrable_iff_integrableOn_Icc_of_le (mod_cast k.le_succ)).mpr + <| (integrablemulsum c ha hb hf_int).mono_set + <| (Set.Icc_subset_Icc_iff (mod_cast k.le_succ)).mpr <| mod_cast (ineqofmemIco hk) + +end abelSummationProof + +/-- Specialized version of `sum_mul_eq_sub_sub_integral_mul` for the case `a = 0`.-/ +theorem sum_mul_eq_sub_integral_mul {b : ℝ} (hb : 0 ≤ b) + (hf_diff : ∀ t ∈ Set.Icc 0 b, DifferentiableAt ℝ f t) + (hf_int : IntegrableOn (deriv f) (Set.Icc 0 b)) : + ∑ k ∈ Icc 0 ⌊b⌋₊, f k * c k = + f b * (∑ k ∈ Icc 0 ⌊b⌋₊, c k) - ∫ t in Set.Ioc 0 b, deriv f t * (∑ k ∈ Icc 0 ⌊t⌋₊, c k) := by + nth_rewrite 1 [Finset.Icc_eq_cons_Ioc (Nat.zero_le _)] + rw [sum_cons, ← Nat.floor_zero (α := ℝ), sum_mul_eq_sub_sub_integral_mul c le_rfl hb hf_diff + hf_int, Nat.floor_zero, Nat.cast_zero, Icc_self, sum_singleton] + ring + +/-- Specialized version of `sum_mul_eq_sub_integral_mul` when the first coefficient of the sequence +`c` is equal to `0`. -/ +theorem sum_mul_eq_sub_integral_mul' (hc : c 0 = 0) (b : ℝ) + (hf_diff : ∀ t ∈ Set.Icc 1 b, DifferentiableAt ℝ f t) + (hf_int : IntegrableOn (deriv f) (Set.Icc 1 b)) : + ∑ k ∈ Icc 0 ⌊b⌋₊, f k * c k = + f b * (∑ k ∈ Icc 0 ⌊b⌋₊, c k) - ∫ t in Set.Ioc 1 b, deriv f t * (∑ k ∈ Icc 0 ⌊t⌋₊, c k) := by + obtain hb | hb := le_or_gt 1 b + · have : 1 ≤ ⌊b⌋₊ := (Nat.one_le_floor_iff _).mpr hb + nth_rewrite 1 [Finset.Icc_eq_cons_Ioc (by linarith), sum_cons, ← Nat.Icc_succ_left, + Finset.Icc_eq_cons_Ioc (by linarith), sum_cons] + rw [Nat.succ_eq_add_one, zero_add, ← Nat.floor_one (α := ℝ), + sum_mul_eq_sub_sub_integral_mul c zero_le_one hb hf_diff hf_int, Nat.floor_one, Nat.cast_one, + Finset.Icc_eq_cons_Ioc zero_le_one, sum_cons, show 1 = 0 + 1 by rfl, Nat.Ioc_succ_singleton, + zero_add, sum_singleton, hc, mul_zero, zero_add] + ring + · simp_rw [Nat.floor_eq_zero.mpr hb, Icc_self, sum_singleton, Nat.cast_zero, hc, mul_zero, + Set.Ioc_eq_empty_of_le hb.le, Measure.restrict_empty, integral_zero_measure, sub_self] diff --git a/Mathlib/NumberTheory/ClassNumber/AdmissibleAbsoluteValue.lean b/Mathlib/NumberTheory/ClassNumber/AdmissibleAbsoluteValue.lean index bdc2a13623ee7..0d34bda52b147 100644 --- a/Mathlib/NumberTheory/ClassNumber/AdmissibleAbsoluteValue.lean +++ b/Mathlib/NumberTheory/ClassNumber/AdmissibleAbsoluteValue.lean @@ -102,7 +102,7 @@ theorem exists_approx_aux (n : ℕ) (h : abv.IsAdmissible) : /-- This proof was nicer prior to https://github.com/leanprover/lean4/pull/4400. Please feel welcome to improve it, by avoiding use of `List.get` in favour of `GetElem`. -/ have : ∀ i h, t ((Finset.univ.filter fun x ↦ t x = s).toList.get ⟨i, h⟩) = s := fun i h ↦ - (Finset.mem_filter.mp (Finset.mem_toList.mp (List.get_mem _ i h))).2 + (Finset.mem_filter.mp (Finset.mem_toList.mp (List.get_mem _ ⟨i, h⟩))).2 simp only [Nat.succ_eq_add_one, Finset.length_toList, List.get_eq_getElem] at this simp only [Nat.succ_eq_add_one, List.get_eq_getElem, Fin.coe_castLE] rw [this _ (Nat.lt_of_le_of_lt (Nat.le_of_lt_succ i₁.2) hs), diff --git a/Mathlib/NumberTheory/DiophantineApproximation.lean b/Mathlib/NumberTheory/DiophantineApproximation.lean index cdccd001950cb..a409528822355 100644 --- a/Mathlib/NumberTheory/DiophantineApproximation.lean +++ b/Mathlib/NumberTheory/DiophantineApproximation.lean @@ -7,6 +7,7 @@ import Mathlib.Algebra.ContinuedFractions.Computation.ApproximationCorollaries import Mathlib.Algebra.ContinuedFractions.Computation.Translations import Mathlib.Data.Real.Irrational import Mathlib.RingTheory.Coprime.Lemmas +import Mathlib.RingTheory.Int.Basic import Mathlib.Tactic.Basic /-! diff --git a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean index 541332309d477..fb438770af84a 100644 --- a/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean +++ b/Mathlib/NumberTheory/EllipticDivisibilitySequence.lean @@ -14,10 +14,10 @@ This file defines the type of an elliptic divisibility sequence (EDS) and a few ## Mathematical background -Let $R$ be a commutative ring. An elliptic sequence is a sequence $W : \mathbb{Z} \to R$ satisfying -$$ W(m + n)W(m - n)W(r)^2 = W(m + r)W(m - r)W(n)^2 - W(n + r)W(n - r)W(m)^2, $$ -for any $m, n, r \in \mathbb{Z}$. A divisibility sequence is a sequence $W : \mathbb{Z} \to R$ -satisfying $W(m) \mid W(n)$ for any $m, n \in \mathbb{Z}$ such that $m \mid n$. +Let `R` be a commutative ring. An elliptic sequence is a sequence `W : ℤ → R` satisfying +`W(m + n)W(m - n)W(r)² = W(m + r)W(m - r)W(n)² - W(n + r)W(n - r)W(m)²` for any `m, n, r ∈ ℤ`. +A divisibility sequence is a sequence `W : ℤ → R` satisfying `W(m) ∣ W(n)` for any `m, n ∈ ℤ` such +that `m ∣ n`. An elliptic divisibility sequence is simply a divisibility sequence that is elliptic. Some examples of EDSs include * the identity sequence, @@ -50,8 +50,8 @@ One reason is to avoid the necessity for ring division by `b` in the inductive d `normEDS b c d (2 * (m + 3))`. The idea is that, it can be shown that `normEDS b c d (2 * (m + 3))` always contains a factor of `b`, so it is possible to remove a factor of `b` *a posteriori*, but stating this lemma requires first defining `normEDS b c d (2 * (m + 3))`, which requires having this -factor of `b` *a priori*. Another reason is to allow the definition of univariate $n$-division -polynomials of elliptic curves, omitting a factor of the bivariate $2$-division polynomial. +factor of `b` *a priori*. Another reason is to allow the definition of univariate `n`-division +polynomials of elliptic curves, omitting a factor of the bivariate `2`-division polynomial. ## References @@ -62,9 +62,13 @@ M Ward, *Memoir on Elliptic Divisibility Sequences* elliptic, divisibility, sequence -/ -universe u v w +universe u v -variable {R : Type u} {S : Type v} [CommRing R] [CommRing S] (W : ℤ → R) (f : R →+* S) +variable {R : Type u} [CommRing R] + +section IsEllDivSequence + +variable (W : ℤ → R) /-- The proposition that a sequence indexed by integers is an elliptic sequence. -/ def IsEllSequence : Prop := @@ -101,6 +105,42 @@ lemma IsDivSequence.smul (h : IsDivSequence W) (x : R) : IsDivSequence (x • W) lemma IsEllDivSequence.smul (h : IsEllDivSequence W) (x : R) : IsEllDivSequence (x • W) := ⟨h.left.smul x, h.right.smul x⟩ +end IsEllDivSequence + +/-- Strong recursion principle for a normalised EDS: if we have + * `P 0`, `P 1`, `P 2`, `P 3`, and `P 4`, + * for all `m : ℕ` we can prove `P (2 * (m + 3))` from `P k` for all `k < 2 * (m + 3)`, and + * for all `m : ℕ` we can prove `P (2 * (m + 2) + 1)` from `P k` for all `k < 2 * (m + 2) + 1`, +then we have `P n` for all `n : ℕ`. -/ +@[elab_as_elim] +noncomputable def normEDSRec' {P : ℕ → Sort u} + (zero : P 0) (one : P 1) (two : P 2) (three : P 3) (four : P 4) + (even : ∀ m : ℕ, (∀ k < 2 * (m + 3), P k) → P (2 * (m + 3))) + (odd : ∀ m : ℕ, (∀ k < 2 * (m + 2) + 1, P k) → P (2 * (m + 2) + 1)) (n : ℕ) : P n := + n.evenOddStrongRec (by rintro (_ | _ | _ | _) h; exacts [zero, two, four, even _ h]) + (by rintro (_ | _ | _) h; exacts [one, three, odd _ h]) + +/-- Recursion principle for a normalised EDS: if we have + * `P 0`, `P 1`, `P 2`, `P 3`, and `P 4`, + * for all `m : ℕ` we can prove `P (2 * (m + 3))` from `P (m + 1)`, `P (m + 2)`, `P (m + 3)`, + `P (m + 4)`, and `P (m + 5)`, and + * for all `m : ℕ` we can prove `P (2 * (m + 2) + 1)` from `P (m + 1)`, `P (m + 2)`, `P (m + 3)`, + and `P (m + 4)`, +then we have `P n` for all `n : ℕ`. -/ +@[elab_as_elim] +noncomputable def normEDSRec {P : ℕ → Sort u} + (zero : P 0) (one : P 1) (two : P 2) (three : P 3) (four : P 4) + (even : ∀ m : ℕ, P (m + 1) → P (m + 2) → P (m + 3) → P (m + 4) → P (m + 5) → P (2 * (m + 3))) + (odd : ∀ m : ℕ, P (m + 1) → P (m + 2) → P (m + 3) → P (m + 4) → P (2 * (m + 2) + 1)) (n : ℕ) : + P n := + normEDSRec' zero one two three four + (fun _ ih => by apply even <;> exact ih _ <| by linarith only) + (fun _ ih => by apply odd <;> exact ih _ <| by linarith only) n + +variable (b c d : R) + +section PreNormEDS + /-- The auxiliary sequence for a normalised EDS `W : ℕ → R`, with initial values `W(0) = 0`, `W(1) = 1`, `W(2) = 1`, `W(3) = c`, and `W(4) = d` and extra parameter `b`. -/ def preNormEDS' (b c d : R) : ℕ → R @@ -123,8 +163,6 @@ def preNormEDS' (b c d : R) : ℕ → R preNormEDS' b c d (m + 2) ^ 2 * preNormEDS' b c d (m + 3) * preNormEDS' b c d (m + 5) - preNormEDS' b c d (m + 1) * preNormEDS' b c d (m + 3) * preNormEDS' b c d (m + 4) ^ 2 -variable (b c d : R) - @[simp] lemma preNormEDS'_zero : preNormEDS' b c d 0 = 0 := by rw [preNormEDS'] @@ -191,22 +229,64 @@ lemma preNormEDS_three : preNormEDS b c d 3 = c := by lemma preNormEDS_four : preNormEDS b c d 4 = d := by erw [preNormEDS_ofNat, preNormEDS'_four] -lemma preNormEDS_odd (m : ℕ) : preNormEDS b c d (2 * (m + 2) + 1) = - preNormEDS b c d (m + 4) * preNormEDS b c d (m + 2) ^ 3 * (if Even m then b else 1) - - preNormEDS b c d (m + 1) * preNormEDS b c d (m + 3) ^ 3 * (if Even m then 1 else b) := by - repeat erw [preNormEDS_ofNat] - exact preNormEDS'_odd .. - -lemma preNormEDS_even (m : ℕ) : preNormEDS b c d (2 * (m + 3)) = +lemma preNormEDS_even_ofNat (m : ℕ) : preNormEDS b c d (2 * (m + 3)) = preNormEDS b c d (m + 2) ^ 2 * preNormEDS b c d (m + 3) * preNormEDS b c d (m + 5) - preNormEDS b c d (m + 1) * preNormEDS b c d (m + 3) * preNormEDS b c d (m + 4) ^ 2 := by repeat erw [preNormEDS_ofNat] exact preNormEDS'_even .. +lemma preNormEDS_odd_ofNat (m : ℕ) : preNormEDS b c d (2 * (m + 2) + 1) = + preNormEDS b c d (m + 4) * preNormEDS b c d (m + 2) ^ 3 * (if Even m then b else 1) - + preNormEDS b c d (m + 1) * preNormEDS b c d (m + 3) ^ 3 * (if Even m then 1 else b) := by + repeat erw [preNormEDS_ofNat] + exact preNormEDS'_odd .. + @[simp] lemma preNormEDS_neg (n : ℤ) : preNormEDS b c d (-n) = -preNormEDS b c d n := by rw [preNormEDS, Int.sign_neg, Int.cast_neg, neg_mul, Int.natAbs_neg, preNormEDS] +lemma preNormEDS_even (m : ℤ) : preNormEDS b c d (2 * m) = + preNormEDS b c d (m - 1) ^ 2 * preNormEDS b c d m * preNormEDS b c d (m + 2) - + preNormEDS b c d (m - 2) * preNormEDS b c d m * preNormEDS b c d (m + 1) ^ 2 := by + induction m using Int.negInduction with + | nat m => + rcases m with _ | _ | _ | m + · simp + · simp + · simp + · simp only [Int.natCast_add, Nat.cast_one] + rw [Int.add_sub_cancel, show (m : ℤ) + 1 + 1 + 1 = m + 1 + 2 by rfl, Int.add_sub_cancel] + exact preNormEDS_even_ofNat .. + | neg h m => + simp_rw [show 2 * -(m : ℤ) = -(2 * m) by omega, show -(m : ℤ) - 1 = -(m + 1) by omega, + show -(m : ℤ) + 2 = -(m - 2) by omega, show -(m : ℤ) - 2 = -(m + 2) by omega, + show -(m : ℤ) + 1 = -(m - 1) by omega, preNormEDS_neg, h m] + ring1 + +lemma preNormEDS_odd (m : ℤ) : preNormEDS b c d (2 * m + 1) = + preNormEDS b c d (m + 2) * preNormEDS b c d m ^ 3 * (if Even m then b else 1) - + preNormEDS b c d (m - 1) * preNormEDS b c d (m + 1) ^ 3 * (if Even m then 1 else b) := by + induction m using Int.negInduction with + | nat m => + rcases m with _ | _ | m + · simp + · simp + · simp only [Int.natCast_add, Nat.cast_one, Int.even_add_one, not_not, Int.even_coe_nat] + rw [Int.add_sub_cancel] + exact preNormEDS_odd_ofNat .. + | neg h m => + rcases m with _ | m + · simp + · simp_rw [Int.natCast_add, Nat.cast_one, show 2 * -(m + 1 : ℤ) + 1 = -(2 * m + 1) by rfl, + show -(m + 1 : ℤ) + 2 = -(m - 1) by omega, show -(m + 1 : ℤ) - 1 = -(m + 2) by rfl, + show -(m + 1 : ℤ) + 1 = -m by omega, preNormEDS_neg, even_neg, Int.even_add_one, ite_not, + h m] + ring1 + +end PreNormEDS + +section NormEDS + /-- The canonical example of a normalised EDS `W : ℤ → R`, with initial values `W(0) = 0`, `W(1) = 1`, `W(2) = b`, `W(3) = c`, and `W(4) = d * b`. @@ -239,53 +319,48 @@ lemma normEDS_three : normEDS b c d 3 = c := by lemma normEDS_four : normEDS b c d 4 = d * b := by erw [normEDS_ofNat, preNormEDS'_four, if_pos <| by decide] -lemma normEDS_odd (m : ℕ) : normEDS b c d (2 * (m + 2) + 1) = - normEDS b c d (m + 4) * normEDS b c d (m + 2) ^ 3 - - normEDS b c d (m + 1) * normEDS b c d (m + 3) ^ 3 := by - repeat erw [normEDS_ofNat] - simp_rw [preNormEDS'_odd, if_neg (m + 2).not_even_two_mul_add_one, Nat.even_add_one, ite_not] - split_ifs <;> ring1 - -lemma normEDS_even (m : ℕ) : normEDS b c d (2 * (m + 3)) * b = +lemma normEDS_even_ofNat (m : ℕ) : normEDS b c d (2 * (m + 3)) * b = normEDS b c d (m + 2) ^ 2 * normEDS b c d (m + 3) * normEDS b c d (m + 5) - normEDS b c d (m + 1) * normEDS b c d (m + 3) * normEDS b c d (m + 4) ^ 2 := by repeat erw [normEDS_ofNat] simp only [preNormEDS'_even, if_pos <| even_two_mul _, Nat.even_add_one, ite_not] split_ifs <;> ring1 +lemma normEDS_odd_ofNat (m : ℕ) : normEDS b c d (2 * (m + 2) + 1) = + normEDS b c d (m + 4) * normEDS b c d (m + 2) ^ 3 - + normEDS b c d (m + 1) * normEDS b c d (m + 3) ^ 3 := by + repeat erw [normEDS_ofNat] + simp_rw [preNormEDS'_odd, if_neg (m + 2).not_even_two_mul_add_one, Nat.even_add_one, ite_not] + split_ifs <;> ring1 + @[simp] lemma normEDS_neg (n : ℤ) : normEDS b c d (-n) = -normEDS b c d n := by simp only [normEDS, preNormEDS_neg, neg_mul, even_neg] -/-- Strong recursion principle for a normalised EDS: if we have - * `P 0`, `P 1`, `P 2`, `P 3`, and `P 4`, - * for all `m : ℕ` we can prove `P (2 * (m + 3))` from `P k` for all `k < 2 * (m + 3)`, and - * for all `m : ℕ` we can prove `P (2 * (m + 2) + 1)` from `P k` for all `k < 2 * (m + 2) + 1`, -then we have `P n` for all `n : ℕ`. -/ -@[elab_as_elim] -noncomputable def normEDSRec' {P : ℕ → Sort u} - (zero : P 0) (one : P 1) (two : P 2) (three : P 3) (four : P 4) - (even : ∀ m : ℕ, (∀ k < 2 * (m + 3), P k) → P (2 * (m + 3))) - (odd : ∀ m : ℕ, (∀ k < 2 * (m + 2) + 1, P k) → P (2 * (m + 2) + 1)) (n : ℕ) : P n := - n.evenOddStrongRec (by rintro (_ | _ | _ | _) h; exacts [zero, two, four, even _ h]) - (by rintro (_ | _ | _) h; exacts [one, three, odd _ h]) +lemma normEDS_even (m : ℤ) : normEDS b c d (2 * m) * b = + normEDS b c d (m - 1) ^ 2 * normEDS b c d m * normEDS b c d (m + 2) - + normEDS b c d (m - 2) * normEDS b c d m * normEDS b c d (m + 1) ^ 2 := by + simp only [normEDS, preNormEDS_even, if_pos <| even_two_mul m, show m + 2 = m + 1 + 1 by ring1, + Int.even_add_one, show m - 2 = m - 1 - 1 by ring1, Int.even_sub_one, ite_not] + by_cases hm : Even m + · simp only [if_pos hm] + ring1 + · simp only [if_neg hm] + ring1 -/-- Recursion principle for a normalised EDS: if we have - * `P 0`, `P 1`, `P 2`, `P 3`, and `P 4`, - * for all `m : ℕ` we can prove `P (2 * (m + 3))` from `P (m + 1)`, `P (m + 2)`, `P (m + 3)`, - `P (m + 4)`, and `P (m + 5)`, and - * for all `m : ℕ` we can prove `P (2 * (m + 2) + 1)` from `P (m + 1)`, `P (m + 2)`, `P (m + 3)`, - and `P (m + 4)`, -then we have `P n` for all `n : ℕ`. -/ -@[elab_as_elim] -noncomputable def normEDSRec {P : ℕ → Sort u} - (zero : P 0) (one : P 1) (two : P 2) (three : P 3) (four : P 4) - (even : ∀ m : ℕ, P (m + 1) → P (m + 2) → P (m + 3) → P (m + 4) → P (m + 5) → P (2 * (m + 3))) - (odd : ∀ m : ℕ, P (m + 1) → P (m + 2) → P (m + 3) → P (m + 4) → P (2 * (m + 2) + 1)) (n : ℕ) : - P n := - normEDSRec' zero one two three four - (fun _ ih => by apply even <;> exact ih _ <| by linarith only) - (fun _ ih => by apply odd <;> exact ih _ <| by linarith only) n +lemma normEDS_odd (m : ℤ) : normEDS b c d (2 * m + 1) = + normEDS b c d (m + 2) * normEDS b c d m ^ 3 - + normEDS b c d (m - 1) * normEDS b c d (m + 1) ^ 3 := by + simp only [normEDS, preNormEDS_odd, if_neg m.not_even_two_mul_add_one] + conv_lhs => rw [← @one_pow R _ 4, ← ite_pow, ← ite_pow] + simp only [show m + 2 = m + 1 + 1 by ring1, Int.even_add_one, Int.even_sub_one, ite_not] + ring1 + +end NormEDS + +section Map + +variable {S : Type v} [CommRing S] (f : R →+* S) lemma map_preNormEDS' (n : ℕ) : f (preNormEDS' b c d n) = preNormEDS' (f b) (f c) (f d) n := by induction n using normEDSRec' with @@ -303,3 +378,5 @@ lemma map_preNormEDS (n : ℤ) : f (preNormEDS b c d n) = preNormEDS (f b) (f c) lemma map_normEDS (n : ℤ) : f (normEDS b c d n) = normEDS (f b) (f c) (f d) n := by rw [normEDS, map_mul, map_preNormEDS, map_pow, apply_ite f, map_one, normEDS] + +end Map diff --git a/Mathlib/NumberTheory/EulerProduct/ExpLog.lean b/Mathlib/NumberTheory/EulerProduct/ExpLog.lean index 8826ef2f3eba6..eb2c16084793f 100644 --- a/Mathlib/NumberTheory/EulerProduct/ExpLog.lean +++ b/Mathlib/NumberTheory/EulerProduct/ExpLog.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Michael Stoll -/ import Mathlib.Analysis.SpecialFunctions.Complex.LogDeriv +import Mathlib.Data.Complex.FiniteDimensional import Mathlib.NumberTheory.EulerProduct.Basic /-! diff --git a/Mathlib/NumberTheory/FLT/Three.lean b/Mathlib/NumberTheory/FLT/Three.lean index 05013ac559c40..fc457ccd599f2 100644 --- a/Mathlib/NumberTheory/FLT/Three.lean +++ b/Mathlib/NumberTheory/FLT/Three.lean @@ -85,7 +85,7 @@ private lemma three_dvd_b_of_dvd_a_of_gcd_eq_one_of_case2 {a b c : ℤ} (ha : a rw [add_comm (a ^ 3), add_assoc, add_comm (a ^ 3), ← add_assoc] at HF refine isCoprime_of_gcd_eq_one_of_FLT ?_ HF convert Hgcd using 2 - rw [Finset.pair_comm, Finset.Insert.comm] + rw [Finset.pair_comm, Finset.insert_comm] by_contra! h3b by_cases h3c : 3 ∣ c · apply h3b @@ -132,15 +132,15 @@ theorem fermatLastTheoremThree_of_three_dvd_only_c rw [← sub_eq_zero, sub_eq_add_neg, ← (show Odd 3 by decide).neg_pow] at hF rcases h1 with (h3a | h3b) | h3c · refine fermatLastTheoremThree_of_dvd_a_of_gcd_eq_one_of_case2 ha h3a ?_ H hF - simp only [← Hgcd, Insert.comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] + simp only [← Hgcd, insert_comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] · rw [add_comm (a ^ 3)] at hF refine fermatLastTheoremThree_of_dvd_a_of_gcd_eq_one_of_case2 hb h3b ?_ H hF - simp only [← Hgcd, Insert.comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] + simp only [← Hgcd, insert_comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] · rw [add_comm _ ((-c) ^ 3), ← add_assoc] at hF refine fermatLastTheoremThree_of_dvd_a_of_gcd_eq_one_of_case2 (neg_ne_zero.2 hc) (by simp [h3c]) ?_ H hF - rw [Finset.Insert.comm (-c), Finset.pair_comm (-c) b] - simp only [← Hgcd, Insert.comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] + rw [Finset.insert_comm (-c), Finset.pair_comm (-c) b] + simp only [← Hgcd, insert_comm, gcd_insert, gcd_singleton, id_eq, ← abs_eq_normalize, abs_neg] section eisenstein @@ -210,8 +210,8 @@ variable [NumberField K] [IsCyclotomicExtension {3} ℚ K] /-- For any `S' : Solution'`, the multiplicity of `λ` in `S'.c` is finite. -/ lemma Solution'.multiplicity_lambda_c_finite : - multiplicity.Finite (hζ.toInteger - 1) S'.c := - multiplicity.finite_of_not_isUnit hζ.zeta_sub_one_prime'.not_unit S'.hc + FiniteMultiplicity (hζ.toInteger - 1) S'.c := + .of_not_isUnit hζ.zeta_sub_one_prime'.not_unit S'.hc section DecidableRel @@ -321,7 +321,6 @@ section DecidableRel variable [NumberField K] [IsCyclotomicExtension {3} ℚ K] [DecidableRel fun (a b : 𝓞 K) ↦ a ∣ b] -open PartENat in /-- Given `S' : Solution'`, we have that `λ ^ 2` divides one amongst `S'.a + S'.b`, `S'.a + η * S'.b` and `S'.a + η ^ 2 * S'.b`. -/ lemma lambda_sq_dvd_or_dvd_or_dvd : @@ -329,14 +328,14 @@ lemma lambda_sq_dvd_or_dvd_or_dvd : by_contra! h rcases h with ⟨h1, h2, h3⟩ rw [← emultiplicity_lt_iff_not_dvd] at h1 h2 h3 - have h1' : multiplicity.Finite (hζ.toInteger - 1) (S'.a + S'.b) := - finite_iff_emultiplicity_ne_top.2 (fun ht ↦ by simp [ht] at h1) - have h2' : multiplicity.Finite (hζ.toInteger - 1) (S'.a + η * S'.b) := by - refine finite_iff_emultiplicity_ne_top.2 (fun ht ↦ ?_) + have h1' : FiniteMultiplicity (hζ.toInteger - 1) (S'.a + S'.b) := + finiteMultiplicity_iff_emultiplicity_ne_top.2 (fun ht ↦ by simp [ht] at h1) + have h2' : FiniteMultiplicity (hζ.toInteger - 1) (S'.a + η * S'.b) := by + refine finiteMultiplicity_iff_emultiplicity_ne_top.2 (fun ht ↦ ?_) rw [coe_eta] at ht simp [ht] at h2 - have h3' : multiplicity.Finite (hζ.toInteger - 1) (S'.a + η ^ 2 * S'.b) := by - refine finite_iff_emultiplicity_ne_top.2 (fun ht ↦ ?_) + have h3' : FiniteMultiplicity (hζ.toInteger - 1) (S'.a + η ^ 2 * S'.b) := by + refine finiteMultiplicity_iff_emultiplicity_ne_top.2 (fun ht ↦ ?_) rw [coe_eta] at ht simp [ht] at h3 rw [h1'.emultiplicity_eq_multiplicity, Nat.cast_lt] at h1 diff --git a/Mathlib/NumberTheory/FactorisationProperties.lean b/Mathlib/NumberTheory/FactorisationProperties.lean index 28cabcc7fd958..f32fbb70c0910 100644 --- a/Mathlib/NumberTheory/FactorisationProperties.lean +++ b/Mathlib/NumberTheory/FactorisationProperties.lean @@ -185,7 +185,7 @@ theorem infinite_even_deficient : {n : ℕ | Even n ∧ n.Deficient}.Infinite := constructor · exact ⟨⟨2 ^ n, by ring⟩, prime_two.deficient_pow⟩ · calc - n ≤ 2 ^ n := Nat.le_of_lt (lt_two_pow n) + n ≤ 2 ^ n := Nat.le_of_lt n.lt_two_pow_self _ < 2 ^ (n + 1) := (Nat.pow_lt_pow_iff_right (Nat.one_lt_two)).mpr (lt_add_one n) theorem infinite_odd_deficient : {n : ℕ | Odd n ∧ n.Deficient}.Infinite := by diff --git a/Mathlib/NumberTheory/FermatPsp.lean b/Mathlib/NumberTheory/FermatPsp.lean index 31cdde409beb6..a620fe11fa855 100644 --- a/Mathlib/NumberTheory/FermatPsp.lean +++ b/Mathlib/NumberTheory/FermatPsp.lean @@ -314,7 +314,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 omega) have : 2 + p ≤ 2 * p := by omega have : p ≤ 2 * p - 2 := le_tsub_of_add_le_left this - exact this.trans_lt (lt_pow_self b_ge_two _) + exact this.trans_lt (Nat.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 diff --git a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean index 7d60dc787c117..f59d387a00ae8 100644 --- a/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean +++ b/Mathlib/NumberTheory/LSeries/HurwitzZetaOdd.lean @@ -453,7 +453,7 @@ lemma hasSum_int_completedHurwitzZetaOdd (a : ℝ) {s : ℂ} (hs : 1 < re s) : rwa [summable_one_div_int_add_rpow] have := mellin_div_const .. ▸ hasSum_mellin_pi_mul_sq' (zero_lt_one.trans hs) hF h_sum refine this.congr_fun fun n ↦ ?_ - simp only [c, mul_one_div, div_mul_eq_mul_div, div_right_comm] + simp only [r, c, mul_one_div, div_mul_eq_mul_div, div_right_comm] /-! ## Non-completed zeta functions diff --git a/Mathlib/NumberTheory/LSeries/Nonvanishing.lean b/Mathlib/NumberTheory/LSeries/Nonvanishing.lean index 7ed3e3b3b2c37..bcec46ab9e9d3 100644 --- a/Mathlib/NumberTheory/LSeries/Nonvanishing.lean +++ b/Mathlib/NumberTheory/LSeries/Nonvanishing.lean @@ -374,8 +374,13 @@ private lemma LFunction_ne_zero_of_not_quadratic_or_ne_one {t : ℝ} (h : χ ^ 2 -- go via absolute value to translate into a statement over `ℝ` replace H := (H₀.trans H).norm_right simp only [norm_eq_abs, abs_ofReal] at H - exact isLittleO_irrefl (.of_forall (fun _ ↦ one_ne_zero)) <| H.of_norm_right.trans_isLittleO - <| isLittleO_id_one.mono nhdsWithin_le_nhds + #adaptation_note + /-- + After https://github.com/leanprover/lean4/pull/6024 + we needed to add `(F' := ℝ)` to `H.of_norm_right`. + -/ + exact isLittleO_irrefl (.of_forall (fun _ ↦ one_ne_zero)) <| + (H.of_norm_right (F' := ℝ)).trans_isLittleO <| isLittleO_id_one.mono nhdsWithin_le_nhds /-- If `χ` is a Dirichlet character, then `L(χ, s)` does not vanish when `s.re = 1` except when `χ` is trivial and `s = 1` (then `L(χ, s)` has a simple pole at `s = 1`). -/ diff --git a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean index b25bd5ca4f8ea..360acae7e6d20 100644 --- a/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean +++ b/Mathlib/NumberTheory/LegendreSymbol/QuadraticChar/Basic.lean @@ -246,7 +246,7 @@ theorem quadraticChar_card_sqrts (hF : ringChar F ≠ 2) (a : F) : ext1 -- Porting note(https://github.com/leanprover-community/mathlib4/issues/5026): -- added (Set.mem_toFinset), Set.mem_setOf - simp only [(Set.mem_toFinset), Set.mem_setOf, not_mem_empty, iff_false] + simp only [s, (Set.mem_toFinset), Set.mem_setOf, not_mem_empty, iff_false] rw [isSquare_iff_exists_sq] at h exact fun h' ↦ h ⟨_, h'.symm⟩ diff --git a/Mathlib/NumberTheory/MaricaSchoenheim.lean b/Mathlib/NumberTheory/MaricaSchoenheim.lean index a88458695d67d..bdbe10e46a529 100644 --- a/Mathlib/NumberTheory/MaricaSchoenheim.lean +++ b/Mathlib/NumberTheory/MaricaSchoenheim.lean @@ -47,13 +47,13 @@ lemma grahamConjecture_of_squarefree {n : ℕ} (f : ℕ → ℕ) (hf' : ∀ k < _ < n := tsub_lt_self hn.bot_lt zero_lt_one · 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] + · simp only [𝒜, forall_mem_diffs, forall_mem_image, mem_Ioo, mem_Iio] rintro i hi j hj rw [← primeFactors_div_gcd (hf' _ hi) (hf' _ hj).ne_zero, prod_primeFactors_of_squarefree <| hf'' _ hi _] exact ⟨Nat.div_pos (gcd_le_left _ (hf' _ hi).ne_zero.bot_lt) <| Nat.gcd_pos_of_pos_left _ (hf' _ hi).ne_zero.bot_lt, Nat.div_lt_of_lt_mul <| this _ hi _ hj⟩ - · simp only [Set.InjOn, mem_coe, forall_mem_diffs, forall_image, mem_Ioo, mem_Iio] + · simp only [𝒜, Set.InjOn, mem_coe, forall_mem_diffs, forall_mem_image, mem_Ioo, mem_Iio] rintro a ha b hb c hc d hd rw [← primeFactors_div_gcd (hf' _ ha) (hf' _ hb).ne_zero, ← primeFactors_div_gcd (hf' _ hc) (hf' _ hd).ne_zero, prod_primeFactors_of_squarefree (hf'' _ ha _), diff --git a/Mathlib/NumberTheory/ModularForms/Basic.lean b/Mathlib/NumberTheory/ModularForms/Basic.lean index 2a7ff22c6f898..67c2a36ff41f4 100644 --- a/Mathlib/NumberTheory/ModularForms/Basic.lean +++ b/Mathlib/NumberTheory/ModularForms/Basic.lean @@ -235,7 +235,6 @@ theorem mul_coe {k_1 k_2 : ℤ} {Γ : Subgroup SL(2, ℤ)} (f : ModularForm Γ k rfl /-- 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' _ := mdifferentiableAt_const @@ -243,6 +242,9 @@ def const (x : ℂ) : ModularForm Γ 0 where simpa only [SlashInvariantForm.const_toFun, ModularForm.is_invariant_const] using atImInfty.const_boundedAtFilter x +@[simp] +lemma const_apply (x : ℂ) (τ : ℍ) : (const x : ModularForm Γ 0) τ = x := rfl + instance : One (ModularForm Γ 0) where one := { const 1 with toSlashInvariantForm := 1 } diff --git a/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean b/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean index e5b29a57f1dd4..ee91db811cdfa 100644 --- a/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean +++ b/Mathlib/NumberTheory/ModularForms/CongruenceSubgroups.lean @@ -64,6 +64,9 @@ theorem Gamma_one_top : Gamma 1 = ⊤ := by ext simp [eq_iff_true_of_subsingleton] +lemma mem_Gamma_one (γ : SL(2, ℤ)) : γ ∈ Γ(1) := by + simp only [Gamma_one_top, Subgroup.mem_top] + theorem Gamma_zero_bot : Gamma 0 = ⊥ := by ext simp only [Gamma_mem, coe_matrix_coe, Int.coe_castRingHom, map_apply, Int.cast_id, diff --git a/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean b/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean index 4e6f7d202b007..b106e2e0d0de9 100644 --- a/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean +++ b/Mathlib/NumberTheory/ModularForms/JacobiTheta/Bounds.lean @@ -249,11 +249,7 @@ lemma isBigO_atTop_F_int_zero_sub (a : UnitAddCircle) : ∃ p, 0 < p ∧ obtain ⟨a, ha, rfl⟩ := a.eq_coe_Ico obtain ⟨p, hp, hp'⟩ := isBigO_atTop_F_nat_zero_sub ha.1 obtain ⟨q, hq, hq'⟩ := isBigO_atTop_F_nat_zero_sub (sub_nonneg.mpr ha.2.le) - have ha' : (a : UnitAddCircle) = 0 ↔ a = 0 := by - rw [← AddCircle.coe_eq_coe_iff_of_mem_Ico (hp := ⟨zero_lt_one' ℝ⟩), QuotientAddGroup.mk_zero] - · rw [zero_add]; exact ha - · simp - simp_rw [ha'] + simp_rw [AddCircle.coe_eq_zero_iff_of_mem_Ico ha] simp_rw [eq_false_intro (by linarith [ha.2] : 1 - a ≠ 0), if_false, sub_zero] at hq' refine ⟨_, lt_min hp hq, ?_⟩ have : (fun t ↦ F_int 0 a t - (if a = 0 then 1 else 0)) =ᶠ[atTop] diff --git a/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean b/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean index ff8f8efa05056..a8e8dfc0a7835 100644 --- a/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean +++ b/Mathlib/NumberTheory/ModularForms/JacobiTheta/TwoVariable.lean @@ -3,9 +3,10 @@ Copyright (c) 2023 David Loeffler. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Loeffler -/ -import Mathlib.Analysis.SpecialFunctions.Gaussian.PoissonSummation import Mathlib.Analysis.Calculus.SmoothSeries import Mathlib.Analysis.NormedSpace.OperatorNorm.Prod +import Mathlib.Analysis.SpecialFunctions.Gaussian.PoissonSummation +import Mathlib.Data.Complex.FiniteDimensional /-! # The two-variable Jacobi theta function diff --git a/Mathlib/NumberTheory/ModularForms/LevelOne.lean b/Mathlib/NumberTheory/ModularForms/LevelOne.lean index 20ba662c6cc3b..5274e56478b89 100644 --- a/Mathlib/NumberTheory/ModularForms/LevelOne.lean +++ b/Mathlib/NumberTheory/ModularForms/LevelOne.lean @@ -3,8 +3,9 @@ Copyright (c) 2024 Chris Birkbeck. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Birkbeck -/ +import Mathlib.Analysis.Complex.AbsMax import Mathlib.NumberTheory.Modular -import Mathlib.NumberTheory.ModularForms.SlashInvariantForms +import Mathlib.NumberTheory.ModularForms.QExpansion /-! # Level one modular forms @@ -14,25 +15,84 @@ TODO: Add finite-dimensionality of these spaces of modular forms. -/ -open UpperHalfPlane ModularGroup SlashInvariantForm ModularForm Complex MatrixGroups +open UpperHalfPlane ModularGroup SlashInvariantForm ModularForm Complex + CongruenceSubgroup Real Function SlashInvariantFormClass ModularFormClass Periodic -lemma SlashInvariantForm.exists_one_half_le_im_and_norm_le {k : ℤ} (hk : k ≤ 0) {F : Type*} - [FunLike F ℍ ℂ] [SlashInvariantFormClass F ⊤ k] (f : F) (τ : ℍ) : - ∃ ξ : ℍ, 1/2 ≤ ξ.im ∧ ‖f τ‖ ≤ ‖f ξ‖ := +local notation "𝕢" => qParam + +variable {F : Type*} [FunLike F ℍ ℂ] {k : ℤ} + +namespace SlashInvariantForm + +variable [SlashInvariantFormClass F Γ(1) k] + +lemma exists_one_half_le_im_and_norm_le (hk : k ≤ 0) (f : F) (τ : ℍ) : + ∃ ξ : ℍ, 1 / 2 ≤ ξ.im ∧ ‖f τ‖ ≤ ‖f ξ‖ := let ⟨γ, hγ, hdenom⟩ := exists_one_half_le_im_smul_and_norm_denom_le τ - ⟨γ • τ, hγ, by simpa only [slash_action_eqn'' _ (show γ ∈ ⊤ by tauto), norm_mul, norm_zpow] - using le_mul_of_one_le_left (norm_nonneg _) <| + ⟨γ • τ, hγ, by simpa only [slash_action_eqn'' _ (mem_Gamma_one γ), + norm_mul, norm_zpow] using le_mul_of_one_le_left (norm_nonneg _) <| one_le_zpow_of_nonpos₀ (norm_pos_iff.2 (denom_ne_zero _ _)) hdenom hk⟩ +variable (k) in /-- If a constant function is modular of weight `k`, then either `k = 0`, or the constant is `0`. -/ -lemma SlashInvariantForm.wt_eq_zero_of_eq_const - {F : Type*} [FunLike F ℍ ℂ] (k : ℤ) [SlashInvariantFormClass F ⊤ k] - {f : F} {c : ℂ} (hf : ∀ τ, f τ = c) : k = 0 ∨ c = 0 := by - have hI := slash_action_eqn'' f (by tauto : ModularGroup.S ∈ ⊤) I - have h2I2 := slash_action_eqn'' f (by tauto : ModularGroup.S ∈ ⊤) ⟨2 * Complex.I, by simp⟩ - simp only [sl_moeb, hf, denom_S, coe_mk_subtype] at hI h2I2 +lemma wt_eq_zero_of_eq_const {f : F} {c : ℂ} (hf : ⇑f = Function.const _ c) : + k = 0 ∨ c = 0 := by + have hI := slash_action_eqn'' f (mem_Gamma_one S) I + have h2I2 := slash_action_eqn'' f (mem_Gamma_one S) ⟨2 * Complex.I, by norm_num⟩ + simp only [sl_moeb, hf, Function.const, denom_S, coe_mk_subtype] at hI h2I2 nth_rw 1 [h2I2] at hI simp only [mul_zpow, coe_I, mul_eq_mul_right_iff, mul_left_eq_self₀] at hI refine hI.imp_left (Or.casesOn · (fun H ↦ ?_) (False.elim ∘ zpow_ne_zero k I_ne_zero)) - rwa [← Complex.ofReal_ofNat, ← ofReal_zpow, ← ofReal_one, ofReal_inj, + rwa [← ofReal_ofNat, ← ofReal_zpow, ← ofReal_one, ofReal_inj, zpow_eq_one_iff_right₀ (by norm_num) (by norm_num)] at H + +end SlashInvariantForm + +namespace ModularFormClass + +variable [ModularFormClass F Γ(1) k] + +private theorem cuspFunction_eqOn_const_of_nonpos_wt (hk : k ≤ 0) (f : F) : + Set.EqOn (cuspFunction 1 f) (const ℂ (cuspFunction 1 f 0)) (Metric.ball 0 1) := by + refine eq_const_of_exists_le (fun q hq ↦ ?_) (exp_nonneg (-π)) ?_ (fun q hq ↦ ?_) + · exact (differentiableAt_cuspFunction 1 f (mem_ball_zero_iff.mp hq)).differentiableWithinAt + · simp only [exp_lt_one_iff, Left.neg_neg_iff, pi_pos] + · simp only [Metric.mem_closedBall, dist_zero_right] + rcases eq_or_ne q 0 with rfl | hq' + · refine ⟨0, by simpa only [norm_zero] using exp_nonneg _, le_rfl⟩ + · obtain ⟨ξ, hξ, hξ₂⟩ := exists_one_half_le_im_and_norm_le hk f + ⟨_, im_invQParam_pos_of_abs_lt_one Real.zero_lt_one (mem_ball_zero_iff.mp hq) hq'⟩ + exact ⟨_, abs_qParam_le_of_one_half_le_im hξ, + by simpa only [← eq_cuspFunction 1 f, Nat.cast_one, coe_mk_subtype, + qParam_right_inv one_ne_zero hq'] using hξ₂⟩ + +private theorem levelOne_nonpos_wt_const (hk : k ≤ 0) (f : F) : + ⇑f = Function.const _ (cuspFunction 1 f 0) := by + ext z + have hQ : 𝕢 1 z ∈ (Metric.ball 0 1) := by + simpa only [Metric.mem_ball, dist_zero_right, Complex.norm_eq_abs, neg_mul, mul_zero, div_one, + Real.exp_zero] using (abs_qParam_lt_iff zero_lt_one 0 z.1).mpr z.2 + simpa only [← eq_cuspFunction 1 f z, Nat.cast_one, Function.const_apply] using + (cuspFunction_eqOn_const_of_nonpos_wt hk f) hQ + +lemma levelOne_neg_weight_eq_zero (hk : k < 0) (f : F) : ⇑f = 0 := by + have hf := levelOne_nonpos_wt_const hk.le f + rcases wt_eq_zero_of_eq_const k hf with rfl | hf₀ + · exact (lt_irrefl _ hk).elim + · rw [hf, hf₀, const_zero] + +lemma levelOne_weight_zero_const [ModularFormClass F Γ(1) 0] (f : F) : + ∃ c, ⇑f = Function.const _ c := + ⟨_, levelOne_nonpos_wt_const le_rfl f⟩ + +end ModularFormClass + +lemma ModularForm.levelOne_weight_zero_rank_one : Module.rank ℂ (ModularForm Γ(1) 0) = 1 := by + refine rank_eq_one (const 1) (by simp [DFunLike.ne_iff]) fun g ↦ ?_ + obtain ⟨c', hc'⟩ := levelOne_weight_zero_const g + aesop + +lemma ModularForm.levelOne_neg_weight_rank_zero (hk : k < 0) : + Module.rank ℂ (ModularForm Γ(1) k) = 0 := by + refine rank_eq_zero_iff.mpr fun f ↦ ⟨_, one_ne_zero, ?_⟩ + simpa only [one_smul, ← DFunLike.coe_injective.eq_iff] using levelOne_neg_weight_eq_zero hk f diff --git a/Mathlib/NumberTheory/ModularForms/QExpansion.lean b/Mathlib/NumberTheory/ModularForms/QExpansion.lean index c236ef8443cf2..c8512f5b76f7e 100644 --- a/Mathlib/NumberTheory/ModularForms/QExpansion.lean +++ b/Mathlib/NumberTheory/ModularForms/QExpansion.lean @@ -20,9 +20,9 @@ application, we show that cusp forms decay exponentially to 0 as `im τ → ∞` * define the `q`-expansion as a formal power series -/ -open ModularForm Complex Filter Asymptotics UpperHalfPlane Function +open ModularForm Complex Filter UpperHalfPlane Function -open scoped Real Topology Manifold MatrixGroups CongruenceSubgroup +open scoped Real MatrixGroups CongruenceSubgroup noncomputable section @@ -36,7 +36,13 @@ theorem Function.Periodic.im_invQParam_pos_of_abs_lt_one 0 < im (Periodic.invQParam h q) := im_invQParam .. ▸ mul_pos_of_neg_of_neg (div_neg_of_neg_of_pos (neg_lt_zero.mpr hh) Real.two_pi_pos) - ((Real.log_neg_iff (Complex.abs.pos hq_ne)).mpr hq) + ((Real.log_neg_iff (abs.pos hq_ne)).mpr hq) + +lemma Function.Periodic.abs_qParam_le_of_one_half_le_im {ξ : ℂ} (hξ : 1 / 2 ≤ ξ.im) : + ‖𝕢 1 ξ‖ ≤ rexp (-π) := by + rwa [Periodic.qParam, ofReal_one, div_one, norm_eq_abs, abs_exp, Real.exp_le_exp, + mul_right_comm, mul_I_re, neg_le_neg_iff, ← ofReal_ofNat, ← ofReal_mul, im_ofReal_mul, + mul_comm _ π, mul_assoc, le_mul_iff_one_le_right Real.pi_pos, ← div_le_iff₀' two_pos] namespace SlashInvariantFormClass diff --git a/Mathlib/NumberTheory/Multiplicity.lean b/Mathlib/NumberTheory/Multiplicity.lean index 85a6e500e4a62..ec4fd6442cf28 100644 --- a/Mathlib/NumberTheory/Multiplicity.lean +++ b/Mathlib/NumberTheory/Multiplicity.lean @@ -90,7 +90,7 @@ theorem odd_sq_dvd_geom_sum₂_sub (hp : Odd p) : (Ideal.Quotient.mk (span {s})) (∑ i ∈ range p, (a + (p : R) * b) ^ i * a ^ (p - 1 - i)) = ∑ i ∈ Finset.range p, mk (span {s}) ((a ^ (i - 1) * (↑p * b) * ↑i + a ^ i) * a ^ (p - 1 - i)) := by - simp_rw [RingHom.map_geom_sum₂, ← map_pow, h1, ← _root_.map_mul] + simp_rw [s, RingHom.map_geom_sum₂, ← map_pow, h1, ← _root_.map_mul] _ = mk (span {s}) (∑ x ∈ Finset.range p, a ^ (x - 1) * (a ^ (p - 1 - x) * (↑p * (b * ↑x)))) + @@ -139,23 +139,26 @@ theorem odd_sq_dvd_geom_sum₂_sub (hp : Odd p) : rw [mul_assoc, mul_assoc] refine mul_eq_zero_of_left ?_ _ refine Ideal.Quotient.eq_zero_iff_mem.mpr ?_ - simp [mem_span_singleton] - -namespace multiplicity + simp [s, mem_span_singleton] section IntegralDomain variable [IsDomain R] -theorem pow_sub_pow_of_prime {p : R} (hp : Prime p) {x y : R} (hxy : p ∣ x - y) (hx : ¬p ∣ x) - {n : ℕ} (hn : ¬p ∣ n) : emultiplicity p (x ^ n - y ^ n) = emultiplicity p (x - y) := by +theorem emultiplicity_pow_sub_pow_of_prime {p : R} (hp : Prime p) {x y : R} + (hxy : p ∣ x - y) (hx : ¬p ∣ x) {n : ℕ} (hn : ¬p ∣ n) : + emultiplicity p (x ^ n - y ^ n) = emultiplicity p (x - y) := by rw [← geom_sum₂_mul, emultiplicity_mul hp, emultiplicity_eq_zero.2 (not_dvd_geom_sum₂ hp hxy hx hn), zero_add] +@[deprecated (since := "2024-11-30")] +alias multiplicity.pow_sub_pow_of_prime := emultiplicity_pow_sub_pow_of_prime + variable (hp : Prime (p : R)) (hp1 : Odd p) (hxy : ↑p ∣ x - y) (hx : ¬↑p ∣ x) include hp hp1 hxy hx -theorem geom_sum₂_eq_one : emultiplicity (↑p) (∑ i ∈ range p, x ^ i * y ^ (p - 1 - i)) = 1 := by +theorem emultiplicity_geom_sum₂_eq_one : + emultiplicity (↑p) (∑ i ∈ range p, x ^ i * y ^ (p - 1 - i)) = 1 := by rw [← Nat.cast_one] refine emultiplicity_eq_coe.2 ⟨?_, ?_⟩ · rw [pow_one] @@ -167,20 +170,29 @@ theorem geom_sum₂_eq_one : emultiplicity (↑p) (∑ i ∈ range p, x ^ i * y rw [pow_two, mul_dvd_mul_iff_left hp.ne_zero] exact mt hp.dvd_of_dvd_pow hx -theorem pow_prime_sub_pow_prime : +@[deprecated (since := "2024-11-30")] +alias multiplicity.geom_sum₂_eq_one := emultiplicity_geom_sum₂_eq_one + +theorem emultiplicity_pow_prime_sub_pow_prime : emultiplicity (↑p) (x ^ p - y ^ p) = emultiplicity (↑p) (x - y) + 1 := by - rw [← geom_sum₂_mul, emultiplicity_mul hp, geom_sum₂_eq_one hp hp1 hxy hx, add_comm] + rw [← geom_sum₂_mul, emultiplicity_mul hp, emultiplicity_geom_sum₂_eq_one hp hp1 hxy hx, add_comm] -theorem pow_prime_pow_sub_pow_prime_pow (a : ℕ) : +@[deprecated (since := "2024-11-30")] +alias multiplicity.pow_prime_sub_pow_prime := emultiplicity_pow_prime_sub_pow_prime + +theorem emultiplicity_pow_prime_pow_sub_pow_prime_pow (a : ℕ) : emultiplicity (↑p) (x ^ p ^ a - y ^ p ^ a) = emultiplicity (↑p) (x - y) + a := by induction' a with a h_ind · rw [Nat.cast_zero, add_zero, pow_zero, pow_one, pow_one] rw [Nat.cast_add, Nat.cast_one, ← add_assoc, ← h_ind, pow_succ, pow_mul, pow_mul] - apply pow_prime_sub_pow_prime hp hp1 + apply emultiplicity_pow_prime_sub_pow_prime hp hp1 · rw [← geom_sum₂_mul] exact dvd_mul_of_dvd_right hxy _ · exact fun h => hx (hp.dvd_of_dvd_pow h) +@[deprecated (since := "2024-11-30")] +alias multiplicity.pow_prime_pow_sub_pow_prime_pow := emultiplicity_pow_prime_pow_sub_pow_prime_pow + end IntegralDomain section LiftingTheExponent @@ -189,17 +201,17 @@ variable (hp : Nat.Prime p) (hp1 : Odd p) include hp hp1 /-- **Lifting the exponent lemma** for odd primes. -/ -theorem Int.pow_sub_pow {x y : ℤ} (hxy : ↑p ∣ x - y) (hx : ¬↑p ∣ x) (n : ℕ) : +theorem Int.emultiplicity_pow_sub_pow {x y : ℤ} (hxy : ↑p ∣ x - y) (hx : ¬↑p ∣ x) (n : ℕ) : emultiplicity (↑p) (x ^ n - y ^ n) = emultiplicity (↑p) (x - y) + emultiplicity p n := by cases' n with n · simp only [emultiplicity_zero, add_top, pow_zero, sub_self] - have h : Finite _ _ := Nat.multiplicity_finite_iff.mpr ⟨hp.ne_one, n.succ_pos⟩ + have h : FiniteMultiplicity _ _ := Nat.finiteMultiplicity_iff.mpr ⟨hp.ne_one, n.succ_pos⟩ simp only [Nat.succ_eq_add_one] at h rcases emultiplicity_eq_coe.mp h.emultiplicity_eq_multiplicity with ⟨⟨k, hk⟩, hpn⟩ conv_lhs => rw [hk, pow_mul, pow_mul] rw [Nat.prime_iff_prime_int] at hp - rw [pow_sub_pow_of_prime hp, pow_prime_pow_sub_pow_prime_pow hp hp1 hxy hx, - h.emultiplicity_eq_multiplicity] + rw [emultiplicity_pow_sub_pow_of_prime hp, + emultiplicity_pow_prime_pow_sub_pow_prime_pow hp hp1 hxy hx, h.emultiplicity_eq_multiplicity] · rw [← geom_sum₂_mul] exact dvd_mul_of_dvd_right hxy _ · exact fun h => hx (hp.dvd_of_dvd_pow h) @@ -208,13 +220,20 @@ theorem Int.pow_sub_pow {x y : ℤ} (hxy : ↑p ∣ x - y) (hx : ¬↑p ∣ x) ( refine hpn ⟨c, ?_⟩ rwa [pow_succ, mul_assoc] -theorem Int.pow_add_pow {x y : ℤ} (hxy : ↑p ∣ x + y) (hx : ¬↑p ∣ x) {n : ℕ} (hn : Odd n) : +@[deprecated (since := "2024-11-30")] +alias multiplicity.Int.pow_sub_pow := Int.emultiplicity_pow_sub_pow + +theorem Int.emultiplicity_pow_add_pow {x y : ℤ} (hxy : ↑p ∣ x + y) (hx : ¬↑p ∣ x) + {n : ℕ} (hn : Odd n) : emultiplicity (↑p) (x ^ n + y ^ n) = emultiplicity (↑p) (x + y) + emultiplicity p n := by rw [← sub_neg_eq_add] at hxy rw [← sub_neg_eq_add, ← sub_neg_eq_add, ← Odd.neg_pow hn] - exact Int.pow_sub_pow hp hp1 hxy hx n + exact Int.emultiplicity_pow_sub_pow hp hp1 hxy hx n + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Int.pow_add_pow := Int.emultiplicity_pow_add_pow -theorem Nat.pow_sub_pow {x y : ℕ} (hxy : p ∣ x - y) (hx : ¬p ∣ x) (n : ℕ) : +theorem Nat.emultiplicity_pow_sub_pow {x y : ℕ} (hxy : p ∣ x - y) (hx : ¬p ∣ x) (n : ℕ) : emultiplicity p (x ^ n - y ^ n) = emultiplicity p (x - y) + emultiplicity p n := by obtain hyx | hyx := le_total y x · iterate 2 rw [← Int.natCast_emultiplicity] @@ -222,20 +241,25 @@ theorem Nat.pow_sub_pow {x y : ℕ} (hxy : p ∣ x - y) (hx : ¬p ∣ x) (n : rw [← Int.natCast_dvd_natCast] at hxy hx rw [Int.natCast_sub hyx] at * push_cast at * - exact Int.pow_sub_pow hp hp1 hxy hx n + exact Int.emultiplicity_pow_sub_pow hp hp1 hxy hx n · simp only [Nat.sub_eq_zero_iff_le.mpr (Nat.pow_le_pow_left hyx n), emultiplicity_zero, Nat.sub_eq_zero_iff_le.mpr hyx, top_add] -theorem Nat.pow_add_pow {x y : ℕ} (hxy : p ∣ x + y) (hx : ¬p ∣ x) {n : ℕ} (hn : Odd n) : +@[deprecated (since := "2024-11-30")] +alias multiplicity.Nat.pow_sub_pow := Nat.emultiplicity_pow_sub_pow + +theorem Nat.emultiplicity_pow_add_pow {x y : ℕ} (hxy : p ∣ x + y) (hx : ¬p ∣ x) + {n : ℕ} (hn : Odd n) : emultiplicity p (x ^ n + y ^ n) = emultiplicity p (x + y) + emultiplicity p n := by iterate 2 rw [← Int.natCast_emultiplicity] rw [← Int.natCast_dvd_natCast] at hxy hx push_cast at * - exact Int.pow_add_pow hp hp1 hxy hx hn + exact Int.emultiplicity_pow_add_pow hp hp1 hxy hx hn -end LiftingTheExponent +@[deprecated (since := "2024-11-30")] +alias multiplicity.Nat.pow_add_pow := Nat.emultiplicity_pow_add_pow -end multiplicity +end LiftingTheExponent end CommRing @@ -294,10 +318,10 @@ theorem Int.two_pow_sub_pow' {x y : ℤ} (n : ℕ) (hxy : 4 ∣ x - y) (hx : ¬2 have hy_odd : Odd y := by simpa using hx_odd.sub_even hxy_even cases' n with n · simp only [pow_zero, sub_self, emultiplicity_zero, Int.ofNat_zero, add_top] - have h : multiplicity.Finite 2 n.succ := Nat.multiplicity_finite_iff.mpr ⟨by norm_num, n.succ_pos⟩ + have h : FiniteMultiplicity 2 n.succ := Nat.finiteMultiplicity_iff.mpr ⟨by norm_num, n.succ_pos⟩ simp only [Nat.succ_eq_add_one] at h rcases emultiplicity_eq_coe.mp h.emultiplicity_eq_multiplicity with ⟨⟨k, hk⟩, hpn⟩ - rw [hk, pow_mul, pow_mul, multiplicity.pow_sub_pow_of_prime, + rw [hk, pow_mul, pow_mul, emultiplicity_pow_sub_pow_of_prime, Int.two_pow_two_pow_sub_pow_two_pow _ hxy hx, ← hk] · norm_cast rw [h.emultiplicity_eq_multiplicity] @@ -332,8 +356,8 @@ theorem Int.two_pow_sub_pow {x y : ℤ} {n : ℕ} (hxy : 2 ∣ x - y) (hx : ¬2 emultiplicity_mul Int.prime_two, emultiplicity_mul Int.prime_two] · suffices emultiplicity (2 : ℤ) ↑(2 : ℕ) = 1 by rw [this, add_comm 1, ← add_assoc] norm_cast - rw [multiplicity.Finite.emultiplicity_self] - rw [Nat.multiplicity_finite_iff] + rw [FiniteMultiplicity.emultiplicity_self] + rw [Nat.finiteMultiplicity_iff] decide · rw [← even_iff_two_dvd, Int.not_even_iff_odd] apply Odd.pow @@ -378,7 +402,7 @@ theorem pow_sub_pow (hyx : y < x) (hxy : p ∣ x - y) (hx : ¬p ∣ x) {n : ℕ} padicValNat p (x ^ n - y ^ n) = padicValNat p (x - y) + padicValNat p n := by rw [← Nat.cast_inj (R := ℕ∞), Nat.cast_add] iterate 3 rw [padicValNat_eq_emultiplicity] - · exact multiplicity.Nat.pow_sub_pow hp.out hp1 hxy hx n + · exact Nat.emultiplicity_pow_sub_pow hp.out hp1 hxy hx n · exact hn.bot_lt · exact Nat.sub_pos_of_lt hyx · exact Nat.sub_pos_of_lt (Nat.pow_lt_pow_left hyx hn) @@ -389,7 +413,7 @@ theorem pow_add_pow (hxy : p ∣ x + y) (hx : ¬p ∣ x) {n : ℕ} (hn : Odd n) · contradiction rw [← Nat.cast_inj (R := ℕ∞), Nat.cast_add] iterate 3 rw [padicValNat_eq_emultiplicity] - · exact multiplicity.Nat.pow_add_pow hp.out hp1 hxy hx hn + · exact Nat.emultiplicity_pow_add_pow hp.out hp1 hxy hx hn · exact Odd.pos hn · simp only [add_pos_iff, Nat.succ_pos', or_true] · exact Nat.lt_add_left _ (pow_pos y.succ_pos _) diff --git a/Mathlib/NumberTheory/NumberField/AdeleRing.lean b/Mathlib/NumberTheory/NumberField/AdeleRing.lean index 7c5add17d6901..1ee25ce15fd5f 100644 --- a/Mathlib/NumberTheory/NumberField/AdeleRing.lean +++ b/Mathlib/NumberTheory/NumberField/AdeleRing.lean @@ -47,11 +47,11 @@ variable (K : Type*) [Field K] The infinite adele ring is the finite product of completions of a number field over its infinite places. See `NumberField.InfinitePlace` for the definition of an infinite place and -`NumberField.InfinitePlace.completion` for the associated completion. +`NumberField.InfinitePlace.Completion` for the associated completion. -/ /-- The infinite adele ring of a number field. -/ -def InfiniteAdeleRing := (v : InfinitePlace K) → v.completion +def InfiniteAdeleRing := (v : InfinitePlace K) → v.Completion namespace InfiniteAdeleRing @@ -82,11 +82,11 @@ abbrev ringEquiv_mixedSpace : InfiniteAdeleRing K ≃+* mixedEmbedding.mixedSpace K := RingEquiv.trans (RingEquiv.piEquivPiSubtypeProd (fun (v : InfinitePlace K) => IsReal v) - (fun (v : InfinitePlace K) => v.completion)) + (fun (v : InfinitePlace K) => v.Completion)) (RingEquiv.prodCongr - (RingEquiv.piCongrRight (fun ⟨_, hv⟩ => Completion.ringEquiv_real_of_isReal hv)) + (RingEquiv.piCongrRight (fun ⟨_, hv⟩ => Completion.ringEquivRealOfIsReal hv)) (RingEquiv.trans - (RingEquiv.piCongrRight (fun v => Completion.ringEquiv_complex_of_isComplex + (RingEquiv.piCongrRight (fun v => Completion.ringEquivComplexOfIsComplex ((not_isReal_iff_isComplex.1 v.2)))) (RingEquiv.piCongrLeft (fun _ => ℂ) <| Equiv.subtypeEquivRight (fun _ => not_isReal_iff_isComplex)))) @@ -94,7 +94,7 @@ abbrev ringEquiv_mixedSpace : @[simp] theorem ringEquiv_mixedSpace_apply (x : InfiniteAdeleRing K) : ringEquiv_mixedSpace K x = - (fun (v : {w : InfinitePlace K // IsReal w}) => extensionEmbedding_of_isReal v.2 (x v), + (fun (v : {w : InfinitePlace K // IsReal w}) => extensionEmbeddingOfIsReal v.2 (x v), fun (v : {w : InfinitePlace K // IsComplex w}) => extensionEmbedding v.1 (x v)) := rfl /-- Transfers the embedding of `x ↦ (x)ᵥ` of the number field `K` into its infinite adele @@ -103,8 +103,8 @@ ring to the mixed embedding `x ↦ (φᵢ(x))ᵢ` of `K` into the space `ℝ ^ r theorem mixedEmbedding_eq_algebraMap_comp {x : K} : mixedEmbedding K x = ringEquiv_mixedSpace K (algebraMap K _ x) := by ext v <;> simp only [ringEquiv_mixedSpace_apply, algebraMap_apply, - ringEquiv_real_of_isReal, ringEquiv_complex_of_isComplex, extensionEmbedding, - extensionEmbedding_of_isReal, extensionEmbedding_of_comp, RingEquiv.coe_ofBijective, + ringEquivRealOfIsReal, ringEquivComplexOfIsComplex, extensionEmbedding, + extensionEmbeddingOfIsReal, extensionEmbedding_of_comp, RingEquiv.coe_ofBijective, RingHom.coe_mk, MonoidHom.coe_mk, OneHom.coe_mk, UniformSpace.Completion.extensionHom] · rw [UniformSpace.Completion.extension_coe (WithAbs.isUniformInducing_of_comp <| v.1.norm_embedding_of_isReal v.2).uniformContinuous x] diff --git a/Mathlib/NumberTheory/NumberField/Completion.lean b/Mathlib/NumberTheory/NumberField/Completion.lean index 5f2aede3c8b65..0d23896da11ed 100644 --- a/Mathlib/NumberTheory/NumberField/Completion.lean +++ b/Mathlib/NumberTheory/NumberField/Completion.lean @@ -19,35 +19,35 @@ of instances is through the use of type synonyms. In this case, we use the type of a semiring. In particular this type synonym depends on an absolute value, which provides a systematic way of assigning and inferring instances of the semiring that also depend on an absolute value. The completion of a field at multiple absolute values is defined in -`Mathlib.Algebra.Ring.WithAbs` as `AbsoluteValue.completion`. The completion of a number +`Mathlib.Algebra.Ring.WithAbs` as `AbsoluteValue.Completion`. The completion of a number field at an infinite place is then derived in this file, as `InfinitePlace` is a subtype of `AbsoluteValue`. ## Main definitions - - `NumberField.InfinitePlace.completion` : the completion of a number field `K` at an infinite + - `NumberField.InfinitePlace.Completion` : the completion of a number field `K` at an infinite place, obtained by completing `K` with respect to the absolute value associated to the infinite place. - `NumberField.InfinitePlace.Completion.extensionEmbedding` : the embedding `v.embedding : K →+* ℂ` - extended to `v.completion →+* ℂ`. - - `NumberField.InfinitePlace.Completion.extensionEmbedding_of_isReal` : if the infinite place `v` + extended to `v.Completion →+* ℂ`. + - `NumberField.InfinitePlace.Completion.extensionEmbeddingOfIsReal` : if the infinite place `v` is real, then this extends the embedding `v.embedding_of_isReal : K →+* ℝ` to - `v.completion →+* ℝ`. + `v.Completion →+* ℝ`. - `NumberField.InfinitePlace.Completion.equiv_real_of_isReal` : the ring isomorphism - `v.completion ≃+* ℝ` when `v` is a real infinite place; the forward direction of this is - `extensionEmbedding_of_isReal`. + `v.Completion ≃+* ℝ` when `v` is a real infinite place; the forward direction of this is + `extensionEmbeddingOfIsReal`. - `NumberField.InfinitePlace.Completion.equiv_complex_of_isComplex` : the ring isomorphism - `v.completion ≃+* ℂ` when `v` is a complex infinite place; the forward direction of this is + `v.Completion ≃+* ℂ` when `v` is a complex infinite place; the forward direction of this is `extensionEmbedding`. ## Main results - `NumberField.Completion.locallyCompactSpace` : the completion of a number field at an infinite place is locally compact. - - `NumberField.Completion.isometry_extensionEmbedding` : the embedding `v.completion →+* ℂ` is + - `NumberField.Completion.isometry_extensionEmbedding` : the embedding `v.Completion →+* ℂ` is an isometry. See also `isometry_extensionEmbedding_of_isReal` for the corresponding result on - `v.completion →+* ℝ` when `v` is real. + `v.Completion →+* ℝ` when `v` is real. - `NumberField.Completion.bijective_extensionEmbedding_of_isComplex` : the embedding - `v.completion →+* ℂ` is bijective when `v` is complex. See also - `bijective_extensionEmebdding_of_isReal` for the corresponding result for `v.completion →+* ℝ` + `v.Completion →+* ℂ` is bijective when `v` is complex. See also + `bijective_extensionEmebdding_of_isReal` for the corresponding result for `v.Completion →+* ℝ` when `v` is real. ## Tags @@ -62,54 +62,75 @@ open AbsoluteValue.Completion variable {K : Type*} [Field K] (v : InfinitePlace K) /-- The completion of a number field at an infinite place. -/ -abbrev completion := v.1.completion +abbrev Completion := v.1.Completion + +@[deprecated (since := "2024-12-01")] alias completion := Completion namespace Completion -instance : NormedField v.completion := +instance : NormedField v.Completion := letI := (WithAbs.isUniformInducing_of_comp v.norm_embedding_eq).completableTopField UniformSpace.Completion.instNormedFieldOfCompletableTopField (WithAbs v.1) -instance : Algebra K v.completion := - inferInstanceAs <| Algebra (WithAbs v.1) v.1.completion +lemma norm_coe (x : WithAbs v.1) : + ‖(x : v.Completion)‖ = v (WithAbs.equiv v.1 x) := + UniformSpace.Completion.norm_coe x + +instance : Algebra K v.Completion := + inferInstanceAs <| Algebra (WithAbs v.1) v.1.Completion + +/-- The coercion from the rationals to its completion along an infinite place is `Rat.cast`. -/ +lemma WithAbs.ratCast_equiv (v : InfinitePlace ℚ) (x : WithAbs v.1) : + Rat.cast (WithAbs.equiv _ x) = (x : v.Completion) := + (eq_ratCast (UniformSpace.Completion.coeRingHom.comp + (WithAbs.ringEquiv v.1).symm.toRingHom) x).symm + +lemma Rat.norm_infinitePlace_completion (v : InfinitePlace ℚ) (x : ℚ) : + ‖(x : v.Completion)‖ = |x| := by + rw [← (WithAbs.equiv v.1).apply_symm_apply x, WithAbs.ratCast_equiv, + norm_coe, (WithAbs.equiv v.1).apply_symm_apply, + Rat.infinitePlace_apply] /-- The completion of a number field at an infinite place is locally compact. -/ -instance locallyCompactSpace : LocallyCompactSpace (v.completion) := +instance locallyCompactSpace : LocallyCompactSpace (v.Completion) := AbsoluteValue.Completion.locallyCompactSpace v.norm_embedding_eq -/-- The embedding associated to an infinite place extended to an embedding `v.completion →+* ℂ`. -/ -def extensionEmbedding : v.completion →+* ℂ := extensionEmbedding_of_comp v.norm_embedding_eq +/-- The embedding associated to an infinite place extended to an embedding `v.Completion →+* ℂ`. -/ +def extensionEmbedding : v.Completion →+* ℂ := extensionEmbedding_of_comp v.norm_embedding_eq -/-- The embedding `K →+* ℝ` associated to a real infinite place extended to `v.completion →+* ℝ`. -/ -def extensionEmbedding_of_isReal {v : InfinitePlace K} (hv : IsReal v) : v.completion →+* ℝ := +/-- The embedding `K →+* ℝ` associated to a real infinite place extended to `v.Completion →+* ℝ`. -/ +def extensionEmbeddingOfIsReal {v : InfinitePlace K} (hv : IsReal v) : v.Completion →+* ℝ := extensionEmbedding_of_comp <| v.norm_embedding_of_isReal hv +@[deprecated (since := "2024-12-07")] +noncomputable alias extensionEmbedding_of_isReal := extensionEmbeddingOfIsReal + @[simp] theorem extensionEmbedding_coe (x : K) : extensionEmbedding v x = v.embedding x := extensionEmbedding_of_comp_coe v.norm_embedding_eq x @[simp] theorem extensionEmbedding_of_isReal_coe {v : InfinitePlace K} (hv : IsReal v) (x : K) : - extensionEmbedding_of_isReal hv x = embedding_of_isReal hv x := + extensionEmbeddingOfIsReal hv x = embedding_of_isReal hv x := extensionEmbedding_of_comp_coe (v.norm_embedding_of_isReal hv) x -/-- The embedding `v.completion →+* ℂ` is an isometry. -/ +/-- The embedding `v.Completion →+* ℂ` is an isometry. -/ theorem isometry_extensionEmbedding : Isometry (extensionEmbedding v) := Isometry.of_dist_eq (extensionEmbedding_dist_eq_of_comp v.norm_embedding_eq) -/-- The embedding `v.completion →+* ℝ` at a real infinite palce is an isometry. -/ +/-- The embedding `v.Completion →+* ℝ` at a real infinite palce is an isometry. -/ theorem isometry_extensionEmbedding_of_isReal {v : InfinitePlace K} (hv : IsReal v) : - Isometry (extensionEmbedding_of_isReal hv) := + Isometry (extensionEmbeddingOfIsReal hv) := Isometry.of_dist_eq (extensionEmbedding_dist_eq_of_comp <| v.norm_embedding_of_isReal hv) -/-- The embedding `v.completion →+* ℂ` has closed image inside `ℂ`. -/ +/-- The embedding `v.Completion →+* ℂ` has closed image inside `ℂ`. -/ theorem isClosed_image_extensionEmbedding : IsClosed (Set.range (extensionEmbedding v)) := (isClosedEmbedding_extensionEmbedding_of_comp v.norm_embedding_eq).isClosed_range -/-- The embedding `v.completion →+* ℝ` associated to a real infinite place has closed image +/-- The embedding `v.Completion →+* ℝ` associated to a real infinite place has closed image inside `ℝ`. -/ theorem isClosed_image_extensionEmbedding_of_isReal {v : InfinitePlace K} (hv : IsReal v) : - IsClosed (Set.range (extensionEmbedding_of_isReal hv)) := + IsClosed (Set.range (extensionEmbeddingOfIsReal hv)) := (isClosedEmbedding_extensionEmbedding_of_comp <| v.norm_embedding_of_isReal hv).isClosed_range theorem subfield_ne_real_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : @@ -120,49 +141,61 @@ theorem subfield_ne_real_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : obtain ⟨r, hr⟩ := hv ▸ extensionEmbedding_coe v x ▸ RingHom.mem_fieldRange_self _ _ simp only [ComplexEmbedding.conjugate_coe_eq, ← hr, Complex.ofRealHom_eq_coe, Complex.conj_ofReal] -/-- If `v` is a complex infinite place, then the embedding `v.completion →+* ℂ` is surjective. -/ +/-- If `v` is a complex infinite place, then the embedding `v.Completion →+* ℂ` is surjective. -/ theorem surjective_extensionEmbedding_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : Function.Surjective (extensionEmbedding v) := by rw [← RingHom.fieldRange_eq_top_iff] exact (Complex.subfield_eq_of_closed <| isClosed_image_extensionEmbedding v).resolve_left <| subfield_ne_real_of_isComplex hv -/-- If `v` is a complex infinite place, then the embedding `v.completion →+* ℂ` is bijective. -/ +/-- If `v` is a complex infinite place, then the embedding `v.Completion →+* ℂ` is bijective. -/ theorem bijective_extensionEmbedding_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : Function.Bijective (extensionEmbedding v) := ⟨(extensionEmbedding v).injective, surjective_extensionEmbedding_of_isComplex hv⟩ -/-- The ring isomorphism `v.completion ≃+* ℂ`, when `v` is complex, given by the bijection -`v.completion →+* ℂ`. -/ -def ringEquiv_complex_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : - v.completion ≃+* ℂ := +/-- The ring isomorphism `v.Completion ≃+* ℂ`, when `v` is complex, given by the bijection +`v.Completion →+* ℂ`. -/ +def ringEquivComplexOfIsComplex {v : InfinitePlace K} (hv : IsComplex v) : + v.Completion ≃+* ℂ := RingEquiv.ofBijective _ (bijective_extensionEmbedding_of_isComplex hv) -/-- If the infinite place `v` is complex, then `v.completion` is isometric to `ℂ`. -/ -def isometryEquiv_complex_of_isComplex {v : InfinitePlace K} (hv : IsComplex v) : - v.completion ≃ᵢ ℂ where - toEquiv := ringEquiv_complex_of_isComplex hv +@[deprecated (since := "2024-12-07")] +noncomputable alias ringEquiv_complex_of_isComplex := ringEquivComplexOfIsComplex + +/-- If the infinite place `v` is complex, then `v.Completion` is isometric to `ℂ`. -/ +def isometryEquivComplexOfIsComplex {v : InfinitePlace K} (hv : IsComplex v) : + v.Completion ≃ᵢ ℂ where + toEquiv := ringEquivComplexOfIsComplex hv isometry_toFun := isometry_extensionEmbedding v -/-- If `v` is a real infinite place, then the embedding `v.completion →+* ℝ` is surjective. -/ +@[deprecated (since := "2024-12-07")] +noncomputable alias isometryEquiv_complex_of_isComplex := isometryEquivComplexOfIsComplex + +/-- If `v` is a real infinite place, then the embedding `v.Completion →+* ℝ` is surjective. -/ theorem surjective_extensionEmbedding_of_isReal {v : InfinitePlace K} (hv : IsReal v) : - Function.Surjective (extensionEmbedding_of_isReal hv) := by + Function.Surjective (extensionEmbeddingOfIsReal hv) := by rw [← RingHom.fieldRange_eq_top_iff, ← Real.subfield_eq_of_closed] exact isClosed_image_extensionEmbedding_of_isReal hv -/-- If `v` is a real infinite place, then the embedding `v.completion →+* ℝ` is bijective. -/ +/-- If `v` is a real infinite place, then the embedding `v.Completion →+* ℝ` is bijective. -/ theorem bijective_extensionEmbedding_of_isReal {v : InfinitePlace K} (hv : IsReal v) : - Function.Bijective (extensionEmbedding_of_isReal hv) := - ⟨(extensionEmbedding_of_isReal hv).injective, surjective_extensionEmbedding_of_isReal hv⟩ + Function.Bijective (extensionEmbeddingOfIsReal hv) := + ⟨(extensionEmbeddingOfIsReal hv).injective, surjective_extensionEmbedding_of_isReal hv⟩ -/-- The ring isomorphism `v.completion ≃+* ℝ`, when `v` is real, given by the bijection -`v.completion →+* ℝ`. -/ -def ringEquiv_real_of_isReal {v : InfinitePlace K} (hv : IsReal v) : v.completion ≃+* ℝ := +/-- The ring isomorphism `v.Completion ≃+* ℝ`, when `v` is real, given by the bijection +`v.Completion →+* ℝ`. -/ +def ringEquivRealOfIsReal {v : InfinitePlace K} (hv : IsReal v) : v.Completion ≃+* ℝ := RingEquiv.ofBijective _ (bijective_extensionEmbedding_of_isReal hv) -/-- If the infinite place `v` is real, then `v.completion` is isometric to `ℝ`. -/ -def isometryEquiv_real_of_isReal {v : InfinitePlace K} (hv : IsReal v) : v.completion ≃ᵢ ℝ where - toEquiv := ringEquiv_real_of_isReal hv +@[deprecated (since := "2024-12-07")] +noncomputable alias ringEquiv_real_of_isReal := ringEquivRealOfIsReal + +/-- If the infinite place `v` is real, then `v.Completion` is isometric to `ℝ`. -/ +def isometryEquivRealOfIsReal {v : InfinitePlace K} (hv : IsReal v) : v.Completion ≃ᵢ ℝ where + toEquiv := ringEquivRealOfIsReal hv isometry_toFun := isometry_extensionEmbedding_of_isReal hv +@[deprecated (since := "2024-12-07")] +noncomputable alias isometryEquiv_real_of_isReal := isometryEquivRealOfIsReal + end NumberField.InfinitePlace.Completion diff --git a/Mathlib/NumberTheory/NumberField/Embeddings.lean b/Mathlib/NumberTheory/NumberField/Embeddings.lean index 3a49b49ab4073..9cda9eb7b84d8 100644 --- a/Mathlib/NumberTheory/NumberField/Embeddings.lean +++ b/Mathlib/NumberTheory/NumberField/Embeddings.lean @@ -259,6 +259,13 @@ instance {K : Type*} [Field K] : FunLike (InfinitePlace K) K ℝ where coe w x := w.1 x coe_injective' _ _ h := Subtype.eq (AbsoluteValue.ext fun x => congr_fun h x) +lemma coe_apply {K : Type*} [Field K] (v : InfinitePlace K) (x : K) : + v x = v.1 x := rfl + +@[ext] +lemma ext {K : Type*} [Field K] (v₁ v₂ : InfinitePlace K) (h : ∀ k, v₁ k = v₂ k) : v₁ = v₂ := + Subtype.ext <| AbsoluteValue.ext h + instance : MonoidWithZeroHomClass (InfinitePlace K) K ℝ where map_mul w _ _ := w.1.map_mul _ _ map_one w := w.1.map_one @@ -631,7 +638,7 @@ lemma comap_surjective [Algebra k K] [Algebra.IsAlgebraic k K] : Function.Surjective (comap · (algebraMap k K)) := fun w ↦ letI := w.embedding.toAlgebra ⟨mk (IsAlgClosed.lift (M := ℂ) (R := k)).toRingHom, - by simp [comap_mk, RingHom.algebraMap_toAlgebra]⟩ + by simp [this, comap_mk, RingHom.algebraMap_toAlgebra]⟩ lemma mult_comap_le (f : k →+* K) (w : InfinitePlace K) : mult (w.comap f) ≤ mult w := by rw [mult, mult] @@ -1066,3 +1073,27 @@ theorem nrRealPlaces_eq_zero_of_two_lt (hk : 2 < k) (hζ : IsPrimitiveRoot ζ k) linarith end IsPrimitiveRoot + +/-! + +## The infinite place of the rationals. + +-/ + +namespace Rat + +open NumberField + +/-- The infinite place of `ℚ`, coming from the canonical map `ℚ → ℂ`. -/ +noncomputable def infinitePlace : InfinitePlace ℚ := .mk (Rat.castHom _) + +@[simp] +lemma infinitePlace_apply (v : InfinitePlace ℚ) (x : ℚ) : v x = |x| := by + rw [NumberField.InfinitePlace.coe_apply] + obtain ⟨_, _, rfl⟩ := v + simp + +instance : Subsingleton (InfinitePlace ℚ) where + allEq a b := by ext; simp + +end Rat diff --git a/Mathlib/NumberTheory/NumberField/FinitePlaces.lean b/Mathlib/NumberTheory/NumberField/FinitePlaces.lean new file mode 100644 index 0000000000000..834648c1e128e --- /dev/null +++ b/Mathlib/NumberTheory/NumberField/FinitePlaces.lean @@ -0,0 +1,236 @@ +/- +Copyright (c) 2024 Fabrizio Barroero. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Fabrizio Barroero +-/ +import Mathlib.Data.Int.WithZero +import Mathlib.NumberTheory.NumberField.Embeddings +import Mathlib.RingTheory.DedekindDomain.AdicValuation +import Mathlib.RingTheory.DedekindDomain.Factorization +import Mathlib.RingTheory.Ideal.Norm.AbsNorm +import Mathlib.Topology.Algebra.Valued.NormedValued + +/-! +# Finite places of number fields +This file defines finite places of a number field `K` as absolute values coming from an embedding +into a completion of `K` associated to a non-zero prime ideal of `𝓞 K`. + +## Main Definitions and Results +* `NumberField.vadicAbv`: a `v`-adic absolute value on `K`. +* `NumberField.FinitePlace`: the type of finite places of a number field `K`. +* `NumberField.FinitePlace.mulSupport_finite`: the `v`-adic absolute value of a non-zero element of +`K` is different from 1 for at most finitely many `v`. + +## Tags +number field, places, finite places +-/ + +open Ideal IsDedekindDomain HeightOneSpectrum NumberField WithZeroMulInt + +namespace NumberField + +section absoluteValue + +variable {K : Type*} [Field K] [NumberField K] (v : HeightOneSpectrum (𝓞 K)) + +/-- The norm of a maximal ideal as an element of `ℝ≥0` is `> 1` -/ +lemma one_lt_norm : 1 < (absNorm v.asIdeal : NNReal) := by + norm_cast + by_contra! h + apply IsPrime.ne_top v.isPrime + rw [← absNorm_eq_one_iff] + have : 0 < absNorm v.asIdeal := by + rw [Nat.pos_iff_ne_zero, absNorm_ne_zero_iff] + exact (v.asIdeal.fintypeQuotientOfFreeOfNeBot v.ne_bot).finite + omega + +private lemma norm_ne_zero : (absNorm v.asIdeal : NNReal) ≠ 0 := ne_zero_of_lt (one_lt_norm v) + +/-- The `v`-adic absolute value on `K` defined as the norm of `v` raised to negative `v`-adic +valuation.-/ +noncomputable def vadicAbv : AbsoluteValue K ℝ where + toFun x := toNNReal (norm_ne_zero v) (v.valuation x) + map_mul' _ _ := by simp only [_root_.map_mul, NNReal.coe_mul] + nonneg' _ := NNReal.zero_le_coe + eq_zero' _ := by simp only [NNReal.coe_eq_zero, map_eq_zero] + add_le' x y := by + -- the triangle inequality is implied by the ultrametric one + apply le_trans _ <| max_le_add_of_nonneg (zero_le ((toNNReal (norm_ne_zero v)) (v.valuation x))) + (zero_le ((toNNReal (norm_ne_zero v)) (v.valuation y))) + have h_mono := (toNNReal_strictMono (one_lt_norm v)).monotone + rw [← h_mono.map_max] --max goes inside withZeroMultIntToNNReal + exact h_mono (v.valuation.map_add x y) + +theorem vadicAbv_def {x : K} : vadicAbv v x = toNNReal (norm_ne_zero v) (v.valuation x) := rfl + +end absoluteValue + +section FinitePlace +variable {K : Type*} [Field K] [NumberField K] (v : HeightOneSpectrum (𝓞 K)) + +/-- The embedding of a number field inside its completion with respect to `v`. -/ +def embedding : K →+* adicCompletion K v := + @UniformSpace.Completion.coeRingHom K _ v.adicValued.toUniformSpace _ _ + +noncomputable instance instRankOneValuedAdicCompletion : + Valuation.RankOne (valuedAdicCompletion K v).v where + hom := { + toFun := toNNReal (norm_ne_zero v) + map_zero' := rfl + map_one' := rfl + map_mul' := MonoidWithZeroHom.map_mul (toNNReal (norm_ne_zero v)) + } + strictMono' := toNNReal_strictMono (one_lt_norm v) + nontrivial' := by + rcases Submodule.exists_mem_ne_zero_of_ne_bot v.ne_bot with ⟨x, hx1, hx2⟩ + use (x : K) + rw [valuedAdicCompletion_eq_valuation' v (x : K)] + constructor + · simpa only [ne_eq, map_eq_zero, NoZeroSMulDivisors.algebraMap_eq_zero_iff] + · apply ne_of_lt + rw [valuation_eq_intValuationDef, intValuation_lt_one_iff_dvd] + exact dvd_span_singleton.mpr hx1 + +/-- The `v`-adic completion of `K` is a normed field. -/ +noncomputable instance instNormedFieldValuedAdicCompletion : NormedField (adicCompletion K v) := + Valued.toNormedField (adicCompletion K v) (WithZero (Multiplicative ℤ)) + +/-- A finite place of a number field `K` is a place associated to an embedding into a completion +with respect to a maximal ideal. -/ +def FinitePlace (K : Type*) [Field K] [NumberField K] := + {w : AbsoluteValue K ℝ // ∃ v : HeightOneSpectrum (𝓞 K), place (embedding v) = w} + +/-- Return the finite place defined by a maximal ideal `v`. -/ +noncomputable def FinitePlace.mk (v : HeightOneSpectrum (𝓞 K)) : FinitePlace K := + ⟨place (embedding v), ⟨v, rfl⟩⟩ + +lemma toNNReal_Valued_eq_vadicAbv (x : K) : + toNNReal (norm_ne_zero v) (Valued.v (self:=v.adicValued) x) = vadicAbv v x := rfl + +/-- The norm of the image after the embedding associated to `v` is equal to the `v`-adic absolute +value. -/ +theorem FinitePlace.norm_def (x : K) : ‖embedding v x‖ = vadicAbv v x := by + simp only [NormedField.toNorm, instNormedFieldValuedAdicCompletion, Valued.toNormedField, + instFieldAdicCompletion, Valued.norm, Valuation.RankOne.hom, MonoidWithZeroHom.coe_mk, + ZeroHom.coe_mk, embedding, UniformSpace.Completion.coeRingHom, RingHom.coe_mk, MonoidHom.coe_mk, + OneHom.coe_mk, Valued.valuedCompletion_apply, toNNReal_Valued_eq_vadicAbv] + +/-- The norm of the image after the embedding associated to `v` is equal to the norm of `v` raised +to the power of the `v`-adic valuation. -/ +theorem FinitePlace.norm_def' (x : K) : ‖embedding v x‖ = toNNReal (norm_ne_zero v) + (v.valuation x) := by + rw [norm_def, vadicAbv_def] + +/-- The norm of the image after the embedding associated to `v` is equal to the norm of `v` raised +to the power of the `v`-adic valuation for integers. -/ +theorem FinitePlace.norm_def_int (x : 𝓞 K) : ‖embedding v x‖ = toNNReal (norm_ne_zero v) + (v.intValuationDef x) := by + rw [norm_def, vadicAbv_def, valuation_eq_intValuationDef] + +open FinitePlace + +/-- The `v`-adic norm of an integer is at most 1. -/ +theorem norm_le_one (x : 𝓞 K) : ‖embedding v x‖ ≤ 1 := by + rw [norm_def', NNReal.coe_le_one, toNNReal_le_one_iff (one_lt_norm v)] + exact valuation_le_one v x + +/-- The `v`-adic norm of an integer is 1 if and only if it is not in the ideal. -/ +theorem norm_eq_one_iff_not_mem (x : 𝓞 K) : ‖(embedding v) x‖ = 1 ↔ x ∉ v.asIdeal := by + rw [norm_def_int, NNReal.coe_eq_one, toNNReal_eq_one_iff (v.intValuationDef x) + (norm_ne_zero v) (one_lt_norm v).ne', ← dvd_span_singleton, + ← intValuation_lt_one_iff_dvd, not_lt] + exact (intValuation_le_one v x).ge_iff_eq.symm + +/-- The `v`-adic norm of an integer is less than 1 if and only if it is in the ideal. -/ +theorem norm_lt_one_iff_mem (x : 𝓞 K) : ‖embedding v x‖ < 1 ↔ x ∈ v.asIdeal := by + rw [norm_def_int, NNReal.coe_lt_one, toNNReal_lt_one_iff (one_lt_norm v), + intValuation_lt_one_iff_dvd] + exact dvd_span_singleton + +end FinitePlace + +namespace FinitePlace +variable {K : Type*} [Field K] [NumberField K] + +instance : FunLike (FinitePlace K) K ℝ where + coe w x := w.1 x + coe_injective' _ _ h := Subtype.eq (AbsoluteValue.ext <| congr_fun h) + +instance : MonoidWithZeroHomClass (FinitePlace K) K ℝ where + map_mul w := w.1.map_mul + map_one w := w.1.map_one + map_zero w := w.1.map_zero + +instance : NonnegHomClass (FinitePlace K) K ℝ where + apply_nonneg w := w.1.nonneg + +@[simp] +theorem apply (v : HeightOneSpectrum (𝓞 K)) (x : K) : mk v x = ‖embedding v x‖ := rfl + +/-- For a finite place `w`, return a maximal ideal `v` such that `w = finite_place v` . -/ +noncomputable def maximalIdeal (w : FinitePlace K) : HeightOneSpectrum (𝓞 K) := w.2.choose + +@[simp] +theorem mk_maximalIdeal (w : FinitePlace K) : mk (maximalIdeal w) = w := Subtype.ext w.2.choose_spec + +@[simp] +theorem norm_embedding_eq (w : FinitePlace K) (x : K) : + ‖embedding (maximalIdeal w) x‖ = w x := by + conv_rhs => rw [← mk_maximalIdeal w, apply] + +theorem pos_iff {w : FinitePlace K} {x : K} : 0 < w x ↔ x ≠ 0 := AbsoluteValue.pos_iff w.1 + +@[simp] +theorem mk_eq_iff {v₁ v₂ : HeightOneSpectrum (𝓞 K)} : mk v₁ = mk v₂ ↔ v₁ = v₂ := by + refine ⟨?_, fun a ↦ by rw [a]⟩ + contrapose! + intro h + rw [DFunLike.ne_iff] + have ⟨x, hx1, hx2⟩ : ∃ x : 𝓞 K, x ∈ v₁.asIdeal ∧ x ∉ v₂.asIdeal := by + by_contra! H + exact h <| HeightOneSpectrum.ext_iff.mpr <| IsMaximal.eq_of_le (isMaximal v₁) IsPrime.ne_top' H + use x + simp only [apply] + rw [← norm_lt_one_iff_mem ] at hx1 + rw [← norm_eq_one_iff_not_mem] at hx2 + linarith + +theorem maximalIdeal_mk (v : HeightOneSpectrum (𝓞 K)) : maximalIdeal (mk v) = v := by + rw [← mk_eq_iff, mk_maximalIdeal] + +lemma maximalIdeal_injective : (fun w : FinitePlace K ↦ maximalIdeal w).Injective := + Function.HasLeftInverse.injective ⟨mk, mk_maximalIdeal⟩ + +lemma maximalIdeal_inj (w₁ w₂ : FinitePlace K) : maximalIdeal w₁ = maximalIdeal w₂ ↔ w₁ = w₂ := + maximalIdeal_injective.eq_iff + +theorem mulSupport_finite_int {x : 𝓞 K} (h_x_nezero : x ≠ 0) : + (Function.mulSupport fun w : FinitePlace K ↦ w x).Finite := by + have (w : FinitePlace K) : w x ≠ 1 ↔ w x < 1 := + ne_iff_lt_iff_le.mpr <| norm_embedding_eq w x ▸ norm_le_one w.maximalIdeal x + simp_rw [Function.mulSupport, this, ← norm_embedding_eq, norm_lt_one_iff_mem, + ← Ideal.dvd_span_singleton] + have h : {v : HeightOneSpectrum (𝓞 K) | v.asIdeal ∣ span {x}}.Finite := by + apply Ideal.finite_factors + simp only [Submodule.zero_eq_bot, ne_eq, span_singleton_eq_bot, h_x_nezero, not_false_eq_true] + have h_inj : Set.InjOn FinitePlace.maximalIdeal {w | w.maximalIdeal.asIdeal ∣ span {x}} := + Function.Injective.injOn maximalIdeal_injective + refine (h.subset ?_).of_finite_image h_inj + simp only [dvd_span_singleton, Set.image_subset_iff, Set.preimage_setOf_eq, subset_refl] + +theorem mulSupport_finite {x : K} (h_x_nezero : x ≠ 0) : + (Function.mulSupport fun w : FinitePlace K ↦ w x).Finite := by + rcases IsFractionRing.div_surjective (A := 𝓞 K) x with ⟨a, b, hb, rfl⟩ + simp_all only [ne_eq, div_eq_zero_iff, NoZeroSMulDivisors.algebraMap_eq_zero_iff, not_or, + map_div₀] + obtain ⟨ha, hb⟩ := h_x_nezero + simp_rw [← RingOfIntegers.coe_eq_algebraMap] + apply ((mulSupport_finite_int ha).union (mulSupport_finite_int hb)).subset + intro w + simp only [Function.mem_mulSupport, ne_eq, Set.mem_union] + contrapose! + simp +contextual only [ne_eq, one_ne_zero, not_false_eq_true, div_self, implies_true] + +end FinitePlace + +end NumberField diff --git a/Mathlib/NumberTheory/NumberField/Units/Basic.lean b/Mathlib/NumberTheory/NumberField/Units/Basic.lean index 7907293a0c950..cecab8573fac6 100644 --- a/Mathlib/NumberTheory/NumberField/Units/Basic.lean +++ b/Mathlib/NumberTheory/NumberField/Units/Basic.lean @@ -5,6 +5,7 @@ Authors: Xavier Roblot -/ import Mathlib.NumberTheory.NumberField.Embeddings import Mathlib.RingTheory.LocalRing.RingHom.Basic +import Mathlib.GroupTheory.Torsion /-! # Units of a number field diff --git a/Mathlib/NumberTheory/Padics/Hensel.lean b/Mathlib/NumberTheory/Padics/Hensel.lean index 74e302eb5dbe2..cf817d16f0a7c 100644 --- a/Mathlib/NumberTheory/Padics/Hensel.lean +++ b/Mathlib/NumberTheory/Padics/Hensel.lean @@ -432,7 +432,7 @@ private theorem soln_unique (z : ℤ_[p]) (hev : F.eval z = 0) _ ≤ 1 * ‖h‖ := by rw [PadicInt.norm_mul] exact mul_le_mul_of_nonneg_right (PadicInt.norm_le_one _) (norm_nonneg _) - _ = ‖z - soln‖ := by simp + _ = ‖z - soln‖ := by simp [h] _ < ‖F.derivative.eval soln‖ := by rw [soln_deriv_norm]; apply soln_dist ) eq_of_sub_eq_zero (by rw [← this]) diff --git a/Mathlib/NumberTheory/Padics/MahlerBasis.lean b/Mathlib/NumberTheory/Padics/MahlerBasis.lean index a6be858db5335..c96931b3ec854 100644 --- a/Mathlib/NumberTheory/Padics/MahlerBasis.lean +++ b/Mathlib/NumberTheory/Padics/MahlerBasis.lean @@ -7,8 +7,10 @@ import Mathlib.Algebra.Group.ForwardDiff import Mathlib.Analysis.Normed.Group.Ultra import Mathlib.NumberTheory.Padics.ProperSpace import Mathlib.RingTheory.Binomial +import Mathlib.Topology.Algebra.InfiniteSum.Nonarchimedean import Mathlib.Topology.Algebra.Polynomial -import Mathlib.Topology.ContinuousMap.Compact +import Mathlib.Topology.ContinuousMap.ZeroAtInfty +import Mathlib.Topology.MetricSpace.Ultra.ContinuousMaps /-! # The Mahler basis of continuous functions @@ -16,13 +18,15 @@ import Mathlib.Topology.ContinuousMap.Compact In this file we introduce the Mahler basis function `mahler k`, for `k : ℕ`, which is the unique continuous map `ℤ_[p] → ℚ_[p]` agreeing with `n ↦ n.choose k` for `n ∈ ℕ`. -We also show that for any continuous function `f` on `ℤ_[p]` (valued in a `p`-adic normed space), -the iterated forward differences `Δ^[n] f 0` tend to 0. For this, we follow the argument of -Bojanić [bojanic74]. +Using this, we prove Mahler's theorem, showing that for any any continuous function `f` on `ℤ_[p]` +(valued in a `p`-adic normed space `E`), the Mahler series `x ↦ ∑' k, mahler k x • Δ^[n] f 0` +converges (uniformly) to `f`, and this construction defines a Banach-space isomorphism between +`C(ℤ_[p], E)` and the space of sequences `ℕ → E` tending to 0. -In future PR's, we will show that the Mahler functions give a Banach basis for the space of -continuous maps `ℤ_[p] → ℚ_[p]`, with the basis coefficients of `f` given by the forward differences -`Δ^[n] f 0`. +For this, we follow the argument of Bojanić [bojanic74]. + +The formalisation of Mahler's theorem presented here is based on code written by Giulio Caflisch +for his bachelor's thesis at ETH Zürich. ## References @@ -35,7 +39,9 @@ continuous maps `ℤ_[p] → ℚ_[p]`, with the basis coefficients of `f` given Bojanic -/ -open Finset fwdDiff IsUltrametricDist NNReal Filter Topology +open Finset IsUltrametricDist NNReal Filter + +open scoped fwdDiff ZeroAtInfty Topology variable {p : ℕ} [hp : Fact p.Prime] @@ -62,7 +68,7 @@ lemma norm_ascPochhammer_le (k : ℕ) (x : ℤ_[p]) : /-- The p-adic integers are a binomial ring, i.e. a ring where binomial coefficients make sense. -/ noncomputable instance instBinomialRing : BinomialRing ℤ_[p] where - nsmul_right_injective n hn := smul_right_injective ℤ_[p] hn + nsmul_right_injective hn := smul_right_injective ℤ_[p] hn -- We define `multichoose` as a fraction in `ℚ_[p]` together with a proof that its norm is `≤ 1`. multichoose x k := ⟨(ascPochhammer ℤ_[p] k).eval x / (k.factorial : ℚ_[p]), by rw [norm_div, div_le_one (by simpa using k.factorial_ne_zero)] @@ -237,4 +243,138 @@ lemma fwdDiff_tendsto_zero (f : C(ℤ_[p], E)) : Tendsto (Δ_[1]^[·] f 0) atTop end norm_fwdDiff +section mahler_coeff + +variable {E : Type*} [NormedAddCommGroup E] [NormedSpace ℚ_[p] E] + (a : E) (n : ℕ) (x : ℤ_[p]) + +/-- +A single term of a Mahler series, given by the product of the scalar-valued continuous map +`mahler n : ℤ_[p] → ℚ_[p]` with a constant vector in some normed `ℚ_[p]`-vector space. +-/ +noncomputable def mahlerTerm : C(ℤ_[p], E) := (mahler n : C(_, ℚ_[p])) • .const _ a + +lemma mahlerTerm_apply : mahlerTerm a n x = mahler n x • a := by + simp only [mahlerTerm, ContinuousMap.smul_apply', ContinuousMap.const_apply] + +lemma norm_mahlerTerm : ‖(mahlerTerm a n : C(ℤ_[p], E))‖ = ‖a‖ := by + simp only [mahlerTerm, ContinuousMap.norm_smul_const, norm_mahler_eq, one_mul] + +/-- A series of the form considered in Mahler's theorem. -/ +noncomputable def mahlerSeries (a : ℕ → E) : C(ℤ_[p], E) := ∑' n, mahlerTerm (a n) n + +variable [IsUltrametricDist E] [CompleteSpace E] {a : ℕ → E} + +/-- A Mahler series whose coefficients tend to 0 is convergent. -/ +lemma hasSum_mahlerSeries (ha : Tendsto a atTop (𝓝 0)) : + HasSum (fun n ↦ mahlerTerm (a n) n) (mahlerSeries a : C(ℤ_[p], E)) := by + refine (NonarchimedeanAddGroup.summable_of_tendsto_cofinite_zero ?_).hasSum + rw [tendsto_zero_iff_norm_tendsto_zero] at ha ⊢ + simpa only [norm_mahlerTerm, Nat.cofinite_eq_atTop] using ha + +/-- Evaluation of a Mahler series is just the pointwise sum. -/ +lemma mahlerSeries_apply (ha : Tendsto a atTop (𝓝 0)) (x : ℤ_[p]) : + mahlerSeries a x = ∑' n, mahler n x • a n := by + simp only [mahlerSeries, ← ContinuousMap.tsum_apply (hasSum_mahlerSeries ha).summable, + mahlerTerm_apply] + +/-- +The value of a Mahler series at a natural number `n` is given by the finite sum of the first `m` +terms, for any `n ≤ m`. +-/ +lemma mahlerSeries_apply_nat (ha : Tendsto a atTop (𝓝 0)) {m n : ℕ} (hmn : m ≤ n) : + mahlerSeries a (m : ℤ_[p]) = ∑ i in range (n + 1), m.choose i • a i := by + have h_van (i) : m.choose (i + (n + 1)) = 0 := Nat.choose_eq_zero_of_lt (by omega) + have aux : Summable fun i ↦ m.choose (i + (n + 1)) • a (i + (n + 1)) := by + simpa only [h_van, zero_smul] using summable_zero + simp only [mahlerSeries_apply ha, mahler_natCast_eq, Nat.cast_smul_eq_nsmul, add_zero, + ← sum_add_tsum_nat_add' (f := fun i ↦ m.choose i • a i) aux, h_van, zero_smul, tsum_zero] + +/-- +The coefficients of a Mahler series can be recovered from the sum by taking forward differences at +`0`. +-/ +lemma fwdDiff_mahlerSeries (ha : Tendsto a atTop (𝓝 0)) (n) : + Δ_[1]^[n] (mahlerSeries a) (0 : ℤ_[p]) = a n := + calc Δ_[1]^[n] (mahlerSeries a) 0 + -- throw away terms after the n'th + _ = Δ_[1]^[n] (fun k ↦ ∑ j ∈ range (n + 1), k.choose j • (a j)) 0 := by + simp only [fwdDiff_iter_eq_sum_shift, zero_add] + refine Finset.sum_congr rfl fun j hj ↦ ?_ + rw [nsmul_one, nsmul_one, + mahlerSeries_apply_nat ha (Nat.lt_succ.mp <| Finset.mem_range.mp hj), Nat.cast_id] + -- bring `Δ_[1]` inside sum + _ = ∑ j ∈ range (n + 1), Δ_[1]^[n] (fun k ↦ k.choose j • (a j)) 0 := by + simp only [fwdDiff_iter_eq_sum_shift, smul_sum] + rw [sum_comm] + -- bring `Δ_[1]` inside scalar-mult + _ = ∑ j ∈ range (n + 1), (Δ_[1]^[n] (fun k ↦ k.choose j : ℕ → ℤ) 0) • (a j) := by + simp only [fwdDiff_iter_eq_sum_shift, zero_add, sum_smul, smul_assoc, Nat.cast_id, + natCast_zsmul] + -- finish using `fwdDiff_iter_choose_zero` + _ = a n := by + simp only [fwdDiff_iter_choose_zero, ite_smul, one_smul, zero_smul, sum_ite_eq, + Finset.mem_range, lt_add_iff_pos_right, zero_lt_one, ↓reduceIte] + +end mahler_coeff + +section mahler_coeff + +variable {p : ℕ} [hp : Fact p.Prime] {E : Type*} + [NormedAddCommGroup E] [NormedSpace ℚ_[p] E] [IsUltrametricDist E] [CompleteSpace E] + +/-- +**Mahler's theorem**: for any continuous function `f` from `ℤ_[p]` to a `p`-adic Banach space, the +Mahler series with coeffients `n ↦ Δ_[1]^[n] f 0` converges to the original function `f`. +-/ +lemma hasSum_mahler (f : C(ℤ_[p], E)) : HasSum (fun n ↦ mahlerTerm (Δ_[1]^[n] f 0) n) f := by + -- First show `∑' n, mahler_term f n` converges to *something*. + have : HasSum (fun n ↦ mahlerTerm (Δ_[1]^[n] f 0) n) + (mahlerSeries (Δ_[1]^[·] f 0) : C(ℤ_[p], E)) := + hasSum_mahlerSeries (PadicInt.fwdDiff_tendsto_zero f) + -- Now show that the sum of the Mahler terms must equal `f` on a dense set, so it is actually `f`. + convert this using 1 + refine ContinuousMap.coe_injective (PadicInt.denseRange_natCast.equalizer + (map_continuous f) (map_continuous _) (funext fun n ↦ ?_)) + simpa only [Function.comp_apply, mahlerSeries_apply_nat (fwdDiff_tendsto_zero f) le_rfl, + zero_add, sum_apply, Pi.smul_apply, nsmul_one] using (shift_eq_sum_fwdDiff_iter 1 f n 0) + +variable (E) in +/-- +The isometric equivalence from `C(ℤ_[p], E)` to the space of sequences in `E` tending to `0` given +by Mahler's theorem, for `E` a nonarchimedean `ℚ_[p]`-Banach space. +-/ +noncomputable def mahlerEquiv : C(ℤ_[p], E) ≃ₗᵢ[ℚ_[p]] C₀(ℕ, E) where + toFun f := ⟨⟨(Δ_[1]^[·] f 0), continuous_of_discreteTopology⟩, + cocompact_eq_atTop (α := ℕ) ▸ fwdDiff_tendsto_zero f⟩ + invFun a := mahlerSeries a + map_add' f g := by + ext x + simp only [ContinuousMap.coe_add, fwdDiff_iter_add, Pi.add_apply, + ZeroAtInftyContinuousMap.coe_mk, ZeroAtInftyContinuousMap.coe_add] + map_smul' r f := by + ext n + simp only [ContinuousMap.coe_smul, RingHom.id_apply, ZeroAtInftyContinuousMap.coe_mk, + ZeroAtInftyContinuousMap.coe_smul, Pi.smul_apply, fwdDiff_iter_const_smul] + left_inv f := (hasSum_mahler f).tsum_eq + right_inv a := ZeroAtInftyContinuousMap.ext <| + fwdDiff_mahlerSeries (cocompact_eq_atTop (α := ℕ) ▸ zero_at_infty a) + norm_map' f := by + simp only [LinearEquiv.coe_mk, ← ZeroAtInftyContinuousMap.norm_toBCF_eq_norm] + apply le_antisymm + · exact BoundedContinuousFunction.norm_le_of_nonempty.mpr + (fun n ↦ norm_fwdDiff_iter_apply_le 1 f 0 n) + · rw [← (hasSum_mahler f).tsum_eq] + refine (norm_tsum_le _).trans (ciSup_le fun n ↦ ?_) + refine le_trans (le_of_eq ?_) (BoundedContinuousFunction.norm_coe_le_norm _ n) + simp only [ZeroAtInftyContinuousMap.toBCF_apply, ZeroAtInftyContinuousMap.coe_mk, + norm_mahlerTerm, (hasSum_mahler f).tsum_eq] + +lemma mahlerEquiv_apply (f : C(ℤ_[p], E)) : mahlerEquiv E f = fun n ↦ Δ_[1]^[n] f 0 := rfl + +lemma mahlerEquiv_symm_apply (a : C₀(ℕ, E)) : (mahlerEquiv E).symm a = (mahlerSeries (p := p) a) := + rfl + +end mahler_coeff + end PadicInt diff --git a/Mathlib/NumberTheory/Padics/PadicIntegers.lean b/Mathlib/NumberTheory/Padics/PadicIntegers.lean index f9e0e0463f74b..33bdb2db15211 100644 --- a/Mathlib/NumberTheory/Padics/PadicIntegers.lean +++ b/Mathlib/NumberTheory/Padics/PadicIntegers.lean @@ -305,7 +305,7 @@ theorem exists_pow_neg_lt {ε : ℝ} (hε : 0 < ε) : ∃ k : ℕ, (p : ℝ) ^ ( apply lt_of_lt_of_le hk norm_cast apply le_of_lt - convert Nat.lt_pow_self _ _ using 1 + convert Nat.lt_pow_self _ using 1 exact hp.1.one_lt · exact mod_cast hp.1.pos @@ -615,8 +615,8 @@ instance isFractionRing : IsFractionRing ℤ_[p] ℚ_[p] where use (⟨a, le_of_eq ha_norm⟩, ⟨(p ^ n : ℤ_[p]), mem_nonZeroDivisors_iff_ne_zero.mpr (NeZero.ne _)⟩) - simp only [map_pow, map_natCast, algebraMap_apply, PadicInt.coe_pow, PadicInt.coe_natCast, - Subtype.coe_mk, Nat.cast_pow] + simp only [a, map_pow, map_natCast, algebraMap_apply, PadicInt.coe_pow, + PadicInt.coe_natCast, Subtype.coe_mk, Nat.cast_pow] exists_of_eq := by simp_rw [algebraMap_apply, Subtype.coe_inj] exact fun h => ⟨1, by rw [h]⟩ diff --git a/Mathlib/NumberTheory/Padics/PadicNorm.lean b/Mathlib/NumberTheory/Padics/PadicNorm.lean index a50570c41e9f1..5e8647a2a1598 100644 --- a/Mathlib/NumberTheory/Padics/PadicNorm.lean +++ b/Mathlib/NumberTheory/Padics/PadicNorm.lean @@ -227,9 +227,9 @@ theorem dvd_iff_norm_le {n : ℕ} {z : ℤ} : ↑(p ^ n) ∣ z ↔ padicNorm p z · rw [zpow_le_zpow_iff_right₀, neg_le_neg_iff, padicValRat.of_int, padicValInt.of_ne_one_ne_zero hp.1.ne_one _] · norm_cast - rw [← multiplicity.Finite.pow_dvd_iff_le_multiplicity] + rw [← FiniteMultiplicity.pow_dvd_iff_le_multiplicity] · norm_cast - · apply Int.multiplicity_finite_iff.2 ⟨by simp [hp.out.ne_one], mod_cast hz⟩ + · apply Int.finiteMultiplicity_iff.2 ⟨by simp [hp.out.ne_one], mod_cast hz⟩ · exact_mod_cast hz · exact_mod_cast hp.out.one_lt diff --git a/Mathlib/NumberTheory/Padics/PadicNumbers.lean b/Mathlib/NumberTheory/Padics/PadicNumbers.lean index d86fe1b155206..7e461266cf61d 100644 --- a/Mathlib/NumberTheory/Padics/PadicNumbers.lean +++ b/Mathlib/NumberTheory/Padics/PadicNumbers.lean @@ -60,7 +60,7 @@ p-adic, p adic, padic, norm, valuation, cauchy, completion, p-adic completion noncomputable section -open Nat multiplicity padicNorm CauSeq CauSeq.Completion Metric +open Nat padicNorm CauSeq CauSeq.Completion Metric /-- The type of Cauchy sequences of rationals with respect to the `p`-adic norm. -/ abbrev PadicSeq (p : ℕ) := diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean index d2df11023e6f1..07c80e89edce7 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Basic.lean @@ -66,12 +66,8 @@ open Nat open Rat -open multiplicity - namespace padicValNat -open multiplicity - variable {p : ℕ} /-- If `p ≠ 0` and `p ≠ 1`, then `padicValNat p p` is `1`. -/ @@ -91,7 +87,7 @@ theorem maxPowDiv_eq_emultiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) : apply Nat.not_lt.mpr <| le_of_dvd hp hn h simp -theorem maxPowDiv_eq_multiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) (h : Finite p n) : +theorem maxPowDiv_eq_multiplicity {p n : ℕ} (hp : 1 < p) (hn : 0 < n) (h : FiniteMultiplicity p n) : p.maxPowDiv n = multiplicity p n := by exact_mod_cast h.emultiplicity_eq_multiplicity ▸ maxPowDiv_eq_emultiplicity hp hn @@ -101,7 +97,7 @@ theorem padicValNat_eq_maxPowDiv : @padicValNat = @maxPowDiv := by ext p n by_cases h : 1 < p ∧ 0 < n · rw [padicValNat_def' h.1.ne' h.2, maxPowDiv_eq_multiplicity h.1 h.2] - exact Nat.multiplicity_finite_iff.2 ⟨h.1.ne', h.2⟩ + exact Nat.finiteMultiplicity_iff.2 ⟨h.1.ne', h.2⟩ · simp only [not_and_or,not_gt_eq,Nat.le_zero] at h apply h.elim · intro h @@ -121,8 +117,6 @@ def padicValInt (p : ℕ) (z : ℤ) : ℕ := namespace padicValInt -open multiplicity - variable {p : ℕ} theorem of_ne_one_ne_zero {z : ℤ} (hp : p ≠ 1) (hz : z ≠ 0) : @@ -163,8 +157,6 @@ lemma padicValRat_def (p : ℕ) (q : ℚ) : namespace padicValRat -open multiplicity - variable {p : ℕ} /-- `padicValRat p q` is symmetric in `q`. -/ @@ -232,13 +224,11 @@ end padicValNat namespace padicValRat -open multiplicity - variable {p : ℕ} [hp : Fact p.Prime] /-- The multiplicity of `p : ℕ` in `a : ℤ` is finite exactly when `a ≠ 0`. -/ -theorem finite_int_prime_iff {a : ℤ} : Finite (p : ℤ) a ↔ a ≠ 0 := by - simp [Int.multiplicity_finite_iff, hp.1.ne_one] +theorem finite_int_prime_iff {a : ℤ} : FiniteMultiplicity (p : ℤ) a ↔ a ≠ 0 := by + simp [Int.finiteMultiplicity_iff, hp.1.ne_one] /-- A rewrite lemma for `padicValRat p q` when `q` is expressed in terms of `Rat.mk`. -/ protected theorem defn (p : ℕ) [hp : Fact p.Prime] {q : ℚ} {n d : ℤ} (hqz : q ≠ 0) @@ -296,8 +286,8 @@ theorem padicValRat_le_padicValRat_iff {n₁ n₂ d₁ d₂ : ℤ} (hn₁ : n₁ (hd₁ : d₁ ≠ 0) (hd₂ : d₂ ≠ 0) : padicValRat p (n₁ /. d₁) ≤ padicValRat p (n₂ /. d₂) ↔ ∀ n : ℕ, (p : ℤ) ^ n ∣ n₁ * d₂ → (p : ℤ) ^ n ∣ n₂ * d₁ := by - have hf1 : Finite (p : ℤ) (n₁ * d₂) := finite_int_prime_iff.2 (mul_ne_zero hn₁ hd₂) - have hf2 : Finite (p : ℤ) (n₂ * d₁) := finite_int_prime_iff.2 (mul_ne_zero hn₂ hd₁) + have hf1 : FiniteMultiplicity (p : ℤ) (n₁ * d₂) := finite_int_prime_iff.2 (mul_ne_zero hn₁ hd₂) + have hf2 : FiniteMultiplicity (p : ℤ) (n₂ * d₁) := finite_int_prime_iff.2 (mul_ne_zero hn₂ hd₁) conv => lhs rw [padicValRat.defn p (Rat.divInt_ne_zero_of_ne_zero hn₁ hd₁) rfl, diff --git a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean index cba87c009c504..39a5bdc501f09 100644 --- a/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean +++ b/Mathlib/NumberTheory/Padics/PadicVal/Defs.lean @@ -22,18 +22,16 @@ universe u open Nat -open multiplicity - variable {p : ℕ} /-- For `p ≠ 1`, the `p`-adic valuation of a natural `n ≠ 0` is the largest natural number `k` such that `p^k` divides `n`. If `n = 0` or `p = 1`, then `padicValNat p q` defaults to `0`. -/ def padicValNat (p : ℕ) (n : ℕ) : ℕ := - if h : p ≠ 1 ∧ 0 < n then Nat.find (multiplicity_finite_iff.2 h) else 0 + if h : p ≠ 1 ∧ 0 < n then Nat.find (finiteMultiplicity_iff.2 h) else 0 theorem padicValNat_def' {n : ℕ} (hp : p ≠ 1) (hn : 0 < n) : padicValNat p n = multiplicity p n := by - simp [padicValNat, hp, hn, multiplicity, emultiplicity, multiplicity_finite_iff.2 ⟨hp, hn⟩] + simp [padicValNat, hp, hn, multiplicity, emultiplicity, finiteMultiplicity_iff.2 ⟨hp, hn⟩] convert (WithTop.untop'_coe ..).symm /-- A simplification of `padicValNat` when one input is prime, by analogy with @@ -46,13 +44,11 @@ theorem padicValNat_def [hp : Fact p.Prime] {n : ℕ} (hn : 0 < n) : `padicValRat_def`. -/ theorem padicValNat_eq_emultiplicity [hp : Fact p.Prime] {n : ℕ} (hn : 0 < n) : padicValNat p n = emultiplicity p n := by - rw [(multiplicity_finite_iff.2 ⟨hp.out.ne_one, hn⟩).emultiplicity_eq_multiplicity] + rw [(finiteMultiplicity_iff.2 ⟨hp.out.ne_one, hn⟩).emultiplicity_eq_multiplicity] exact_mod_cast padicValNat_def hn namespace padicValNat -open multiplicity - open List /-- `padicValNat p 0` is `0` for any `p`. -/ @@ -86,7 +82,7 @@ theorem le_padicValNat_iff_replicate_subperm_primeFactorsList {a b : ℕ} {n : (hb : b ≠ 0) : n ≤ padicValNat a b ↔ replicate n a <+~ b.primeFactorsList := by rw [← le_emultiplicity_iff_replicate_subperm_primeFactorsList ha hb, - Nat.multiplicity_finite_iff.2 ⟨ha.ne_one, Nat.pos_of_ne_zero hb⟩ + Nat.finiteMultiplicity_iff.2 ⟨ha.ne_one, Nat.pos_of_ne_zero hb⟩ |>.emultiplicity_eq_multiplicity, ← padicValNat_def' ha.ne_one (Nat.pos_of_ne_zero hb), Nat.cast_le] diff --git a/Mathlib/NumberTheory/Padics/RingHoms.lean b/Mathlib/NumberTheory/Padics/RingHoms.lean index 2fed1c971dbfe..53244367555c2 100644 --- a/Mathlib/NumberTheory/Padics/RingHoms.lean +++ b/Mathlib/NumberTheory/Padics/RingHoms.lean @@ -119,7 +119,8 @@ theorem norm_sub_modPart (h : ‖(r : ℚ_[p])‖ ≤ 1) : ‖(⟨r, h⟩ - modP rw [norm_lt_one_iff_dvd, ← (isUnit_den r h).dvd_mul_right] suffices ↑p ∣ r.num - n * r.den by convert (Int.castRingHom ℤ_[p]).map_dvd this - simp only [sub_mul, Int.cast_natCast, eq_intCast, Int.cast_mul, sub_left_inj, Int.cast_sub] + simp only [n, sub_mul, Int.cast_natCast, eq_intCast, Int.cast_mul, sub_left_inj, + Int.cast_sub] apply Subtype.coe_injective simp only [coe_mul, Subtype.coe_mk, coe_natCast] rw_mod_cast [@Rat.mul_den_eq_num r] diff --git a/Mathlib/NumberTheory/RamificationInertia/Basic.lean b/Mathlib/NumberTheory/RamificationInertia/Basic.lean index 92cb53f8ad16f..d0291b1916d6f 100644 --- a/Mathlib/NumberTheory/RamificationInertia/Basic.lean +++ b/Mathlib/NumberTheory/RamificationInertia/Basic.lean @@ -181,7 +181,9 @@ theorem ramificationIdx_ne_zero (hp0 : map f p ≠ ⊥) (hP : P.IsPrime) (le : m end IsDedekindDomain -variable (f p P) +variable (f p P) [Algebra R S] + +local notation "f" => algebraMap R S open Classical in /-- The inertia degree of `P : Ideal S` lying over `p : Ideal R` is the degree of the @@ -194,31 +196,31 @@ and there is an algebra structure `R / p → S / P`. -/ noncomputable def inertiaDeg : ℕ := if hPp : comap f P = p then - letI : Algebra (R ⧸ p) (S ⧸ P) := Quotient.algebraQuotientOfLEComap (le_of_eq hPp.symm) + letI : Algebra (R ⧸ p) (S ⧸ P) := Quotient.algebraQuotientOfLEComap hPp.ge finrank (R ⧸ p) (S ⧸ P) else 0 -- Useful for the `nontriviality` tactic using `comap_eq_of_scalar_tower_quotient`. @[simp] theorem inertiaDeg_of_subsingleton [hp : p.IsMaximal] [hQ : Subsingleton (S ⧸ P)] : - inertiaDeg f p P = 0 := by + inertiaDeg p P = 0 := by have := Ideal.Quotient.subsingleton_iff.mp hQ subst this exact dif_neg fun h => hp.ne_top <| h.symm.trans comap_top @[simp] -theorem inertiaDeg_algebraMap [Algebra R S] [P.LiesOver p] [p.IsMaximal] : - inertiaDeg (algebraMap R S) p P = finrank (R ⧸ p) (S ⧸ P) := by +theorem inertiaDeg_algebraMap [P.LiesOver p] [p.IsMaximal] : + inertiaDeg p P = finrank (R ⧸ p) (S ⧸ P) := by nontriviality S ⧸ P using inertiaDeg_of_subsingleton, finrank_zero_of_subsingleton rw [inertiaDeg, dif_pos (over_def P p).symm] -theorem inertiaDeg_pos [p.IsMaximal] [Algebra R S] [Module.Finite R S] - [P.LiesOver p] : 0 < inertiaDeg (algebraMap R S) p P := +theorem inertiaDeg_pos [p.IsMaximal] [Module.Finite R S] + [P.LiesOver p] : 0 < inertiaDeg p P := haveI : Nontrivial (S ⧸ P) := Quotient.nontrivial_of_liesOver_of_isPrime P p finrank_pos.trans_eq (inertiaDeg_algebraMap p P).symm -lemma inertiaDeg_comap_eq [Algebra R S] (e : S ≃ₐ[R] S₁) (P : Ideal S₁) [p.IsMaximal] : - inertiaDeg (algebraMap R S) p (P.comap e) = inertiaDeg (algebraMap R S₁) p P := by +lemma inertiaDeg_comap_eq (e : S ≃ₐ[R] S₁) (P : Ideal S₁) [p.IsMaximal] : + inertiaDeg p (P.comap e) = inertiaDeg p P := by have he : (P.comap e).comap (algebraMap R S) = p ↔ P.comap (algebraMap R S₁) = p := by rw [← comap_coe e, comap_comap, ← e.toAlgHom_toRingHom, AlgHom.comp_algebraMap] by_cases h : P.LiesOver p @@ -227,9 +229,9 @@ lemma inertiaDeg_comap_eq [Algebra R S] (e : S ≃ₐ[R] S₁) (P : Ideal S₁) · rw [inertiaDeg, dif_neg (fun eq => h ⟨(he.mp eq).symm⟩)] rw [inertiaDeg, dif_neg (fun eq => h ⟨eq.symm⟩)] -lemma inertiaDeg_map_eq [p.IsMaximal] [Algebra R S] (P : Ideal S) +lemma inertiaDeg_map_eq [p.IsMaximal] (P : Ideal S) {E : Type*} [EquivLike E S S₁] [AlgEquivClass E R S S₁] (e : E) : - inertiaDeg (algebraMap R S₁) p (P.map e) = inertiaDeg (algebraMap R S) p P := by + inertiaDeg p (P.map e) = inertiaDeg p P := by rw [show P.map e = _ from map_comap_of_equiv (e : S ≃+* S₁)] exact p.inertiaDeg_comap_eq (e : S ≃ₐ[R] S₁).symm P @@ -447,6 +449,9 @@ end FinrankQuotientMap section FactLeComap +variable [Algebra R S] + +local notation "f" => algebraMap R S local notation "e" => ramificationIdx f p P /-- `R / p` has a canonical map to `S / (P ^ e)`, where `e` is the ramification index @@ -462,17 +467,15 @@ theorem Quotient.algebraMap_quotient_pow_ramificationIdx (x : R) : This can't be an instance since the map `f : R → S` is generally not inferrable. -/ -def Quotient.algebraQuotientOfRamificationIdxNeZero [hfp : NeZero (ramificationIdx f p P)] : +def Quotient.algebraQuotientOfRamificationIdxNeZero [hfp : NeZero e] : Algebra (R ⧸ p) (S ⧸ P) := Quotient.algebraQuotientOfLEComap (le_comap_of_ramificationIdx_ne_zero hfp.out) -set_option synthInstance.checkSynthOrder false -- Porting note: this is okay by the remark below --- In this file, the value for `f` can be inferred. attribute [local instance] Ideal.Quotient.algebraQuotientOfRamificationIdxNeZero @[simp] theorem Quotient.algebraMap_quotient_of_ramificationIdx_neZero - [NeZero (ramificationIdx f p P)] (x : R) : + [NeZero e] (x : R) : algebraMap (R ⧸ p) (S ⧸ P) (Ideal.Quotient.mk p x) = Ideal.Quotient.mk P (f x) := rfl /-- The inclusion `(P^(i + 1) / P^e) ⊂ (P^i / P^e)`. -/ @@ -485,7 +488,7 @@ def powQuotSuccInclusion (i : ℕ) : map_smul' _ _ := rfl theorem powQuotSuccInclusion_injective (i : ℕ) : - Function.Injective (powQuotSuccInclusion f p P i) := by + Function.Injective (powQuotSuccInclusion p P i) := by rw [← LinearMap.ker_eq_bot, LinearMap.ker_eq_bot'] rintro ⟨x, hx⟩ hx0 rw [Subtype.ext_iff] at hx0 ⊢ @@ -497,7 +500,7 @@ and `quotientRangePowQuotSuccInclusionEquiv` for this as a linear equivalence. -/ noncomputable def quotientToQuotientRangePowQuotSuccAux {i : ℕ} {a : S} (a_mem : a ∈ P ^ i) : S ⧸ P → - (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion f p P i) := + (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion p P i) := Quotient.map' (fun x : S => ⟨_, Ideal.mem_map_of_mem _ (Ideal.mul_mem_right x _ a_mem)⟩) fun x y h => by rw [Submodule.quotientRel_def] at h ⊢ @@ -508,18 +511,19 @@ noncomputable def quotientToQuotientRangePowQuotSuccAux {i : ℕ} {a : S} (a_mem Subtype.coe_mk, _root_.map_mul, map_sub, mul_sub] theorem quotientToQuotientRangePowQuotSuccAux_mk {i : ℕ} {a : S} (a_mem : a ∈ P ^ i) (x : S) : - quotientToQuotientRangePowQuotSuccAux f p P a_mem (Submodule.Quotient.mk x) = + quotientToQuotientRangePowQuotSuccAux p P a_mem (Submodule.Quotient.mk x) = Submodule.Quotient.mk ⟨_, Ideal.mem_map_of_mem _ (Ideal.mul_mem_right x _ a_mem)⟩ := by apply Quotient.map'_mk'' section -variable [hfp : NeZero (ramificationIdx f p P)] +variable [hfp : NeZero (ramificationIdx (algebraMap R S) p P)] /-- `S ⧸ P` embeds into the quotient by `P^(i+1) ⧸ P^e` as a subspace of `P^i ⧸ P^e`. -/ -noncomputable def quotientToQuotientRangePowQuotSucc {i : ℕ} {a : S} (a_mem : a ∈ P ^ i) : +noncomputable def quotientToQuotientRangePowQuotSucc + {i : ℕ} {a : S} (a_mem : a ∈ P ^ i) : S ⧸ P →ₗ[R ⧸ p] - (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion f p P i) where - toFun := quotientToQuotientRangePowQuotSuccAux f p P a_mem + (P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion p P i) where + toFun := quotientToQuotientRangePowQuotSuccAux p P a_mem map_add' := by intro x y; refine Quotient.inductionOn' x fun x => Quotient.inductionOn' y fun y => ?_ simp only [Submodule.Quotient.mk''_eq_mk, ← Submodule.Quotient.mk_add, @@ -536,13 +540,13 @@ noncomputable def quotientToQuotientRangePowQuotSucc {i : ℕ} {a : S} (a_mem : ring theorem quotientToQuotientRangePowQuotSucc_mk {i : ℕ} {a : S} (a_mem : a ∈ P ^ i) (x : S) : - quotientToQuotientRangePowQuotSucc f p P a_mem (Submodule.Quotient.mk x) = + quotientToQuotientRangePowQuotSucc p P a_mem (Submodule.Quotient.mk x) = Submodule.Quotient.mk ⟨_, Ideal.mem_map_of_mem _ (Ideal.mul_mem_right x _ a_mem)⟩ := - quotientToQuotientRangePowQuotSuccAux_mk f p P a_mem x + quotientToQuotientRangePowQuotSuccAux_mk p P a_mem x theorem quotientToQuotientRangePowQuotSucc_injective [IsDedekindDomain S] [P.IsPrime] {i : ℕ} (hi : i < e) {a : S} (a_mem : a ∈ P ^ i) (a_not_mem : a ∉ P ^ (i + 1)) : - Function.Injective (quotientToQuotientRangePowQuotSucc f p P a_mem) := fun x => + Function.Injective (quotientToQuotientRangePowQuotSucc 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_right hi @@ -562,7 +566,7 @@ theorem quotientToQuotientRangePowQuotSucc_injective [IsDedekindDomain S] [P.IsP theorem quotientToQuotientRangePowQuotSucc_surjective [IsDedekindDomain S] (hP0 : P ≠ ⊥) [hP : P.IsPrime] {i : ℕ} (hi : i < e) {a : S} (a_mem : a ∈ P ^ i) (a_not_mem : a ∉ P ^ (i + 1)) : - Function.Surjective (quotientToQuotientRangePowQuotSucc f p P a_mem) := by + Function.Surjective (quotientToQuotientRangePowQuotSucc p P a_mem) := by rintro ⟨⟨⟨x⟩, hx⟩⟩ 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, @@ -592,15 +596,15 @@ theorem quotientToQuotientRangePowQuotSucc_surjective [IsDedekindDomain S] `R ⧸ p`-linearly isomorphic to `S ⧸ P`. -/ noncomputable def quotientRangePowQuotSuccInclusionEquiv [IsDedekindDomain S] [P.IsPrime] (hP : P ≠ ⊥) {i : ℕ} (hi : i < e) : - ((P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion f p P i)) + ((P ^ i).map (Ideal.Quotient.mk (P ^ e)) ⧸ LinearMap.range (powQuotSuccInclusion p P i)) ≃ₗ[R ⧸ p] S ⧸ P := by choose a a_mem a_not_mem using SetLike.exists_of_lt (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 - · exact quotientToQuotientRangePowQuotSucc_surjective f p P hP hi a_mem a_not_mem + · exact quotientToQuotientRangePowQuotSucc p P a_mem + · exact quotientToQuotientRangePowQuotSucc_injective p P hi a_mem a_not_mem + · exact quotientToQuotientRangePowQuotSucc_surjective p P hP hi a_mem a_not_mem /-- Since the inclusion `(P^(i + 1) / P^e) ⊂ (P^i / P^e)` has a kernel isomorphic to `P / S`, `[P^i / P^e : R / p] = [P^(i+1) / P^e : R / p] + [P / S : R / p]` -/ @@ -609,9 +613,9 @@ theorem rank_pow_quot_aux [IsDedekindDomain S] [p.IsMaximal] [P.IsPrime] (hP0 : Module.rank (R ⧸ p) (Ideal.map (Ideal.Quotient.mk (P ^ e)) (P ^ i)) = Module.rank (R ⧸ p) (S ⧸ P) + Module.rank (R ⧸ p) (Ideal.map (Ideal.Quotient.mk (P ^ e)) (P ^ (i + 1))) := by - rw [← rank_range_of_injective _ (powQuotSuccInclusion_injective f p P i), - (quotientRangePowQuotSuccInclusionEquiv f p P hP0 hi).symm.rank_eq] - exact (Submodule.rank_quotient_add_rank (LinearMap.range (powQuotSuccInclusion f p P i))).symm + rw [← rank_range_of_injective _ (powQuotSuccInclusion_injective p P i), + (quotientRangePowQuotSuccInclusionEquiv p P hP0 hi).symm.rank_eq] + exact (Submodule.rank_quotient_add_rank (LinearMap.range (powQuotSuccInclusion p P i))).symm theorem rank_pow_quot [IsDedekindDomain S] [p.IsMaximal] [P.IsPrime] (hP0 : P ≠ ⊥) (i : ℕ) (hi : i ≤ e) : @@ -623,7 +627,7 @@ theorem rank_pow_quot [IsDedekindDomain S] [p.IsMaximal] [P.IsPrime] (hP0 : P = (e - i) • Module.rank (R ⧸ p) (S ⧸ P) refine Nat.decreasingInduction' (P := Q) (fun j lt_e _le_j ih => ?_) hi ?_ · dsimp only [Q] - rw [rank_pow_quot_aux f p P _ lt_e, ih, ← succ_nsmul', Nat.sub_succ, ← Nat.succ_eq_add_one, + rw [rank_pow_quot_aux p P _ lt_e, ih, ← succ_nsmul', Nat.sub_succ, ← Nat.succ_eq_add_one, Nat.succ_pred_eq_of_pos (Nat.sub_pos_of_lt lt_e)] assumption · dsimp only [Q] @@ -642,7 +646,7 @@ theorem rank_prime_pow_ramificationIdx [IsDedekindDomain S] [p.IsMaximal] [P.IsP (@Algebra.toModule _ _ _ _ <| @Quotient.algebraQuotientOfRamificationIdxNeZero _ _ _ _ _ _ _ ⟨he⟩) := by letI : NeZero e := ⟨he⟩ - have := rank_pow_quot f p P hP0 0 (Nat.zero_le e) + have := rank_pow_quot p P hP0 0 (Nat.zero_le e) rw [pow_zero, Nat.sub_zero, Ideal.one_eq_top, Ideal.map_top] at this exact (rank_top (R ⧸ p) _).symm.trans this @@ -656,8 +660,8 @@ theorem finrank_prime_pow_ramificationIdx [IsDedekindDomain S] (hP0 : P ≠ ⊥) (@Algebra.toModule _ _ _ _ <| @Quotient.algebraQuotientOfRamificationIdxNeZero _ _ _ _ _ _ _ ⟨he⟩) := by letI : NeZero e := ⟨he⟩ - letI : Algebra (R ⧸ p) (S ⧸ P) := Quotient.algebraQuotientOfRamificationIdxNeZero f p P - have hdim := rank_prime_pow_ramificationIdx _ _ _ hP0 he + letI : Algebra (R ⧸ p) (S ⧸ P) := Quotient.algebraQuotientOfRamificationIdxNeZero p P + have hdim := rank_prime_pow_ramificationIdx _ _ hP0 he by_cases hP : FiniteDimensional (R ⧸ p) (S ⧸ P) · haveI := hP haveI := (finiteDimensional_iff_of_rank_eq_nsmul he hdim).mpr hP @@ -709,7 +713,7 @@ instance Factors.liesOver [p.IsMaximal] (P : (factors (map (algebraMap R S) p)). theorem Factors.finrank_pow_ramificationIdx [p.IsMaximal] (P : (factors (map (algebraMap R S) p)).toFinset) : finrank (R ⧸ p) (S ⧸ (P : Ideal S) ^ ramificationIdx (algebraMap R S) p P) = - ramificationIdx (algebraMap R S) p P * inertiaDeg (algebraMap R S) p P := by + ramificationIdx (algebraMap R S) p P * inertiaDeg p (P : Ideal S) := by rw [finrank_prime_pow_ramificationIdx, inertiaDeg_algebraMap] exacts [Factors.ne_bot p P, NeZero.ne _] @@ -772,10 +776,10 @@ theorem sum_ramification_inertia (K L : Type*) [Field K] [Field L] [IsDedekindDo [Algebra R L] [IsScalarTower R S L] [IsScalarTower R K L] [Module.Finite R S] [p.IsMaximal] (hp0 : p ≠ ⊥) : (∑ P ∈ (factors (map (algebraMap R S) p)).toFinset, - ramificationIdx (algebraMap R S) p P * inertiaDeg (algebraMap R S) p P) = + ramificationIdx (algebraMap R S) p P * inertiaDeg p P) = finrank K L := by set e := ramificationIdx (algebraMap R S) p - set f := inertiaDeg (algebraMap R S) p + set f := inertiaDeg p (S := S) calc (∑ P ∈ (factors (map (algebraMap R S) p)).toFinset, e P * f P) = ∑ P ∈ (factors (map (algebraMap R S) p)).toFinset.attach, @@ -822,17 +826,6 @@ theorem ramificationIdx_tower [IsDedekindDomain S] [IsDedekindDomain T] {f : R exact add_right_eq_self.mpr <| Decidable.byContradiction fun h ↦ hntq <| hcp.trans_le <| sup_le hg <| le_of_dvd <| dvd_of_mem_normalizedFactors <| Multiset.count_ne_zero.mp h -theorem inertiaDeg_tower {f : R →+* S} {g : S →+* T} {p : Ideal R} {P : Ideal S} {I : Ideal T} - [p.IsMaximal] [P.IsMaximal] (hp : p = comap f P) (hP : P = comap g I) : - inertiaDeg (g.comp f) p I = inertiaDeg f p P * inertiaDeg g P I := by - have h : comap (g.comp f) I = p := by rw [hp, hP, comap_comap] - simp only [inertiaDeg, dif_pos hp.symm, dif_pos hP.symm, dif_pos h] - letI : Algebra (R ⧸ p) (S ⧸ P) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq hp) - letI : Algebra (S ⧸ P) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq hP) - letI : Algebra (R ⧸ p) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap (le_of_eq h.symm) - letI : IsScalarTower (R ⧸ p) (S ⧸ P) (T ⧸ I) := IsScalarTower.of_algebraMap_eq (by rintro ⟨⟩; rfl) - exact (finrank_mul_finrank (R ⧸ p) (S ⧸ P) (T ⧸ I)).symm - variable [Algebra R S] [Algebra S T] [Algebra R T] [IsScalarTower R S T] /-- Let `T / S / R` be a tower of algebras, `p, P, Q` be ideals in `R, S, T` respectively, @@ -850,10 +843,20 @@ theorem ramificationIdx_algebra_tower [IsDedekindDomain S] [IsDedekindDomain T] and `p` and `P` are maximal. If `p = P ∩ S` and `P = I ∩ S`, then `f (I | p) = f (P | p) * f (I | P)`. -/ theorem inertiaDeg_algebra_tower (p : Ideal R) (P : Ideal S) (I : Ideal T) [p.IsMaximal] - [P.IsMaximal] [P.LiesOver p] [I.LiesOver P] : inertiaDeg (algebraMap R T) p I = - inertiaDeg (algebraMap R S) p P * inertiaDeg (algebraMap S T) P I := by - rw [IsScalarTower.algebraMap_eq R S T] - exact inertiaDeg_tower (over_def P p) (over_def I P) + [P.IsMaximal] [P.LiesOver p] [I.LiesOver P] : inertiaDeg p I = + inertiaDeg p P * inertiaDeg P I := by + have h₁ := P.over_def p + have h₂ := I.over_def P + have h₃ := (LiesOver.trans I P p).over + simp only [inertiaDeg, dif_pos h₁.symm, dif_pos h₂.symm, dif_pos h₃.symm] + letI : Algebra (R ⧸ p) (S ⧸ P) := Ideal.Quotient.algebraQuotientOfLEComap h₁.le + letI : Algebra (S ⧸ P) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap h₂.le + letI : Algebra (R ⧸ p) (T ⧸ I) := Ideal.Quotient.algebraQuotientOfLEComap h₃.le + letI : IsScalarTower (R ⧸ p) (S ⧸ P) (T ⧸ I) := IsScalarTower.of_algebraMap_eq <| by + rintro ⟨x⟩; exact congr_arg _ (IsScalarTower.algebraMap_apply R S T x) + exact (finrank_mul_finrank (R ⧸ p) (S ⧸ P) (T ⧸ I)).symm + +@[deprecated (since := "2024-12-09")] alias inertiaDeg_tower := inertiaDeg_algebra_tower end tower diff --git a/Mathlib/NumberTheory/SmoothNumbers.lean b/Mathlib/NumberTheory/SmoothNumbers.lean index 5072132e5f160..dfc8479b15721 100644 --- a/Mathlib/NumberTheory/SmoothNumbers.lean +++ b/Mathlib/NumberTheory/SmoothNumbers.lean @@ -234,7 +234,7 @@ def equivProdNatFactoredNumbers {s : Finset ℕ} {p : ℕ} (hp : p.Prime) (hs : (filter _ <| perm_primeFactorsList_mul (pow_ne_zero e hp.ne_zero) hm₀).trans ?_ rw [filter_append, hp.primeFactorsList_pow, filter_eq_nil_iff.mpr fun q hq ↦ by rw [mem_replicate] at hq; simp [hq.2, hs], - nil_append, filter_eq_self.mpr fun q hq ↦ by simp only [hm q hq, decide_True]] + nil_append, filter_eq_self.mpr fun q hq ↦ by simp only [hm q hq, decide_true]] right_inv := by rintro ⟨m, hm₀, hm⟩ simp only [Set.coe_setOf, Set.mem_setOf_eq, Subtype.mk.injEq] @@ -244,8 +244,8 @@ def equivProdNatFactoredNumbers {s : Finset ℕ} {p : ℕ} (hp : p.Prime) (hs : refine (filter_congr fun q hq ↦ ?_).symm simp only [decide_not, Bool.not_eq_true', decide_eq_false_iff_not, decide_eq_true_eq] rcases Finset.mem_insert.mp <| hm _ hq with h | h - · simp only [h, hs, decide_False, Bool.not_false, decide_True] - · simp only [h, decide_True, Bool.not_true, false_eq_decide_iff] + · simp only [h, hs, decide_false, Bool.not_false, decide_true] + · simp only [h, decide_true, Bool.not_true, false_eq_decide_iff] exact fun H ↦ hs <| H ▸ h refine prod_eq <| (filter_eq m.primeFactorsList p).symm ▸ this ▸ perm_append_comm.trans ?_ simp only [decide_not] diff --git a/Mathlib/NumberTheory/WellApproximable.lean b/Mathlib/NumberTheory/WellApproximable.lean index 7b72f49ff60e8..a4baa65fee7dd 100644 --- a/Mathlib/NumberTheory/WellApproximable.lean +++ b/Mathlib/NumberTheory/WellApproximable.lean @@ -274,7 +274,7 @@ theorem addWellApproximable_ae_empty_or_univ (δ : ℕ → ℝ) (hδ : Tendsto exact fun contra => h_ndiv (mul_dvd_mul_left p contra) replace h_div : n / p * p = n := Nat.div_mul_cancel h_div have hf : f = (fun y => x + y) ∘ fun y => p • y := by - ext; simp [add_comm x] + ext; simp [f, add_comm x] simp_rw [Function.comp_apply, le_eq_subset] rw [sSupHom.setImage_toFun, hf, image_comp] have := @monotone_image 𝕊 𝕊 fun y => x + y @@ -309,7 +309,8 @@ theorem addWellApproximable_ae_empty_or_univ (δ : ℕ → ℝ) (hδ : Tendsto · cases' hA p with _ h; · contradiction simp only [h, union_ae_eq_univ_of_ae_eq_univ_left] · cases' hB p with _ h; · contradiction - simp only [h, union_ae_eq_univ_of_ae_eq_univ_left, union_ae_eq_univ_of_ae_eq_univ_right] + simp only [h, union_ae_eq_univ_of_ae_eq_univ_left, + union_ae_eq_univ_of_ae_eq_univ_right] /-- A general version of **Dirichlet's approximation theorem**. @@ -335,7 +336,7 @@ lemma _root_.NormedAddCommGroup.exists_norm_nsmul_le {A : Type*} rw [← (isClosed_iUnion_of_finite hB).measure_eq_univ_iff_eq (μ := μ)] refine le_antisymm (μ.mono (subset_univ _)) ?_ simp_rw [measure_iUnion h (fun _ ↦ measurableSet_closedBall), tsum_fintype, - μ.addHaar_closedBall_center, Finset.sum_const, Finset.card_univ, Nat.card_fintypeIcc, + B, μ.addHaar_closedBall_center, Finset.sum_const, Finset.card_univ, Nat.card_fintypeIcc, tsub_zero] exact hδ replace hδ : 0 ≤ δ/2 := by diff --git a/Mathlib/NumberTheory/Zsqrtd/Basic.lean b/Mathlib/NumberTheory/Zsqrtd/Basic.lean index 914914db4f6cb..b7c9c0db4e4a0 100644 --- a/Mathlib/NumberTheory/Zsqrtd/Basic.lean +++ b/Mathlib/NumberTheory/Zsqrtd/Basic.lean @@ -558,7 +558,7 @@ instance decidableNonnegg (c d a b) : Decidable (Nonnegg c d a b) := by instance decidableNonneg : ∀ a : ℤ√d, Decidable (Nonneg a) | ⟨_, _⟩ => Zsqrtd.decidableNonnegg _ _ _ _ -instance decidableLE : @DecidableRel (ℤ√d) (· ≤ ·) := fun _ _ => decidableNonneg _ +instance decidableLE : DecidableRel (α := ℤ√d) (· ≤ ·) := fun _ _ => decidableNonneg _ open Int in theorem nonneg_cases : ∀ {a : ℤ√d}, Nonneg a → ∃ x y : ℕ, a = ⟨x, y⟩ ∨ a = ⟨x, -y⟩ ∨ a = ⟨-x, y⟩ diff --git a/Mathlib/Order/Antisymmetrization.lean b/Mathlib/Order/Antisymmetrization.lean index 75caf3593c355..2a5cced208b85 100644 --- a/Mathlib/Order/Antisymmetrization.lean +++ b/Mathlib/Order/Antisymmetrization.lean @@ -161,7 +161,7 @@ instance [WellFoundedLT α] : WellFoundedLT (Antisymmetrization α (· ≤ ·)) instance [WellFoundedGT α] : WellFoundedGT (Antisymmetrization α (· ≤ ·)) := wellFoundedGT_antisymmetrization_iff.mpr ‹_› -instance [@DecidableRel α (· ≤ ·)] [@DecidableRel α (· < ·)] [IsTotal α (· ≤ ·)] : +instance [DecidableRel (α := α) (· ≤ ·)] [DecidableRel (α := α) (· < ·)] [IsTotal α (· ≤ ·)] : LinearOrder (Antisymmetrization α (· ≤ ·)) := { instPartialOrderAntisymmetrization with le_total := fun a b => Quotient.inductionOn₂' a b <| total_of (· ≤ ·), diff --git a/Mathlib/Order/Basic.lean b/Mathlib/Order/Basic.lean index caa54da5b5024..d5004d18c24ab 100644 --- a/Mathlib/Order/Basic.lean +++ b/Mathlib/Order/Basic.lean @@ -289,7 +289,8 @@ section PartialOrder variable [PartialOrder α] {a b : α} -- See Note [decidable namespace] -protected theorem Decidable.le_iff_eq_or_lt [@DecidableRel α (· ≤ ·)] : a ≤ b ↔ a = b ∨ a < b := +protected theorem Decidable.le_iff_eq_or_lt [DecidableRel (α := α) (· ≤ ·)] : + a ≤ b ↔ a = b ∨ a < b := Decidable.le_iff_lt_or_eq.trans or_comm theorem le_iff_eq_or_lt : a ≤ b ↔ a = b ∨ a < b := le_iff_lt_or_eq.trans or_comm @@ -302,7 +303,7 @@ lemma eq_iff_not_lt_of_le (hab : a ≤ b) : a = b ↔ ¬ a < b := by simp [hab, alias LE.le.eq_iff_not_lt := eq_iff_not_lt_of_le -- See Note [decidable namespace] -protected theorem Decidable.eq_iff_le_not_lt [@DecidableRel α (· ≤ ·)] : +protected theorem Decidable.eq_iff_le_not_lt [DecidableRel (α := α) (· ≤ ·)] : a = b ↔ a ≤ b ∧ ¬a < b := ⟨fun h ↦ ⟨h.le, h ▸ lt_irrefl _⟩, fun ⟨h₁, h₂⟩ ↦ h₁.antisymm <| Decidable.byContradiction fun h₃ ↦ h₂ (h₁.lt_of_not_le h₃)⟩ @@ -529,11 +530,20 @@ theorem PartialOrder.ext {A B : PartialOrder α} ext x y exact H x y +theorem PartialOrder.ext_lt {A B : PartialOrder α} + (H : ∀ x y : α, (haveI := A; x < y) ↔ x < y) : A = B := by + ext x y + rw [le_iff_lt_or_eq, @le_iff_lt_or_eq _ A, H] + theorem LinearOrder.ext {A B : LinearOrder α} (H : ∀ x y : α, (haveI := A; x ≤ y) ↔ x ≤ y) : A = B := by ext x y exact H x y +theorem LinearOrder.ext_lt {A B : LinearOrder α} + (H : ∀ x y : α, (haveI := A; x < y) ↔ x < y) : A = B := + LinearOrder.toPartialOrder_injective (PartialOrder.ext_lt H) + /-- Given a relation `R` on `β` and a function `f : α → β`, the preimage relation on `α` is defined by `x ≤ y ↔ f x ≤ f y`. It is the unique relation on `α` making `f` a `RelEmbedding` (assuming `f` is injective). -/ @@ -689,6 +699,9 @@ instance (α : Type*) [LE α] : LE αᵒᵈ := instance (α : Type*) [LT α] : LT αᵒᵈ := ⟨fun x y : α ↦ y < x⟩ +instance instOrd (α : Type*) [Ord α] : Ord αᵒᵈ where + compare := fun (a b : α) ↦ compare b a + instance instSup (α : Type*) [Min α] : Max αᵒᵈ := ⟨((· ⊓ ·) : α → α → α)⟩ @@ -706,6 +719,7 @@ instance instPartialOrder (α : Type*) [PartialOrder α] : PartialOrder αᵒᵈ instance instLinearOrder (α : Type*) [LinearOrder α] : LinearOrder αᵒᵈ where __ := inferInstanceAs (PartialOrder αᵒᵈ) + __ := inferInstanceAs (Ord αᵒᵈ) le_total := fun a b : α ↦ le_total b a max := fun a b ↦ (min a b : α) min := fun a b ↦ (max a b : α) @@ -713,6 +727,10 @@ instance instLinearOrder (α : Type*) [LinearOrder α] : LinearOrder αᵒᵈ wh max_def := fun a b ↦ show (min .. : α) = _ by rw [min_comm, min_def]; rfl decidableLE := (inferInstance : DecidableRel (fun a b : α ↦ b ≤ a)) decidableLT := (inferInstance : DecidableRel (fun a b : α ↦ b < a)) + decidableEq := (inferInstance : DecidableEq α) + compare_eq_compareOfLessAndEq a b := by + simp only [compare, LinearOrder.compare_eq_compareOfLessAndEq, compareOfLessAndEq, eq_comm] + rfl /-- The opposite linear order to a given linear order -/ def _root_.LinearOrder.swap (α : Type*) (_ : LinearOrder α) : LinearOrder α := @@ -720,16 +738,19 @@ def _root_.LinearOrder.swap (α : Type*) (_ : LinearOrder α) : LinearOrder α : instance : ∀ [Inhabited α], Inhabited αᵒᵈ := fun [x : Inhabited α] => x +theorem Ord.dual_dual (α : Type*) [H : Ord α] : OrderDual.instOrd αᵒᵈ = H := + rfl + theorem Preorder.dual_dual (α : Type*) [H : Preorder α] : OrderDual.instPreorder αᵒᵈ = H := - Preorder.ext fun _ _ ↦ Iff.rfl + rfl theorem instPartialOrder.dual_dual (α : Type*) [H : PartialOrder α] : OrderDual.instPartialOrder αᵒᵈ = H := - PartialOrder.ext fun _ _ ↦ Iff.rfl + rfl theorem instLinearOrder.dual_dual (α : Type*) [H : LinearOrder α] : OrderDual.instLinearOrder αᵒᵈ = H := - LinearOrder.ext fun _ _ ↦ Iff.rfl + rfl end OrderDual @@ -762,6 +783,10 @@ theorem compl_le [LinearOrder α] : (· ≤ · : α → α → _)ᶜ = (· > ·) theorem compl_gt [LinearOrder α] : (· > · : α → α → _)ᶜ = (· ≤ ·) := by ext; simp [compl] theorem compl_ge [LinearOrder α] : (· ≥ · : α → α → _)ᶜ = (· < ·) := by ext; simp [compl] +instance Ne.instIsEquiv_compl : IsEquiv α (· ≠ ·)ᶜ := by + convert eq_isEquiv α + simp [compl] + /-! ### Order instances on the function space -/ @@ -1085,11 +1110,11 @@ instance preorder [Preorder α] (p : α → Prop) : Preorder (Subtype p) := instance partialOrder [PartialOrder α] (p : α → Prop) : PartialOrder (Subtype p) := PartialOrder.lift (fun (a : Subtype p) ↦ (a : α)) Subtype.coe_injective -instance decidableLE [Preorder α] [h : @DecidableRel α (· ≤ ·)] {p : α → Prop} : - @DecidableRel (Subtype p) (· ≤ ·) := fun a b ↦ h a b +instance decidableLE [Preorder α] [h : DecidableRel (α := α) (· ≤ ·)] {p : α → Prop} : + DecidableRel (α := Subtype p) (· ≤ ·) := fun a b ↦ h a b -instance decidableLT [Preorder α] [h : @DecidableRel α (· < ·)] {p : α → Prop} : - @DecidableRel (Subtype p) (· < ·) := fun a b ↦ h a b +instance decidableLT [Preorder α] [h : DecidableRel (α := α) (· < ·)] {p : α → Prop} : + DecidableRel (α := Subtype p) (· < ·) := fun a b ↦ h a b /-- A subtype of a linear order is a linear order. We explicitly give the proofs of decidable equality and decidable order in order to ensure the decidability instances are all definitionally diff --git a/Mathlib/Order/BoundedOrder/Lattice.lean b/Mathlib/Order/BoundedOrder/Lattice.lean index 42c1cf7c0ac57..3c06e09a51844 100644 --- a/Mathlib/Order/BoundedOrder/Lattice.lean +++ b/Mathlib/Order/BoundedOrder/Lattice.lean @@ -7,19 +7,19 @@ import Mathlib.Order.BoundedOrder.Basic import Mathlib.Order.Lattice /-! -# bounded lattices +# Bounded lattices This file defines top and bottom elements (greatest and least elements) of a type, the bounded -variants of different kinds of lattices, sets up the typeclass hierarchy between them and provides +variants of different kinds of lattices, sets up the typeclass hierarchy between them, and provides instances for `Prop` and `fun`. ## Common lattices -* Distributive lattices with a bottom element. Notated by `[DistribLattice α] [OrderBot α]` +* Distributive lattices with a bottom element. Notated by `[DistribLattice α] [OrderBot α]`. It captures the properties of `Disjoint` that are common to `GeneralizedBooleanAlgebra` and `DistribLattice` when `OrderBot`. * Bounded and distributive lattice. Notated by `[DistribLattice α] [BoundedOrder α]`. - Typical examples include `Prop` and `Det α`. + Typical examples include `Prop` and `Set α`. -/ open Function OrderDual diff --git a/Mathlib/Order/Bounds/Image.lean b/Mathlib/Order/Bounds/Image.lean index 910c466332520..4ef77e7f9e476 100644 --- a/Mathlib/Order/Bounds/Image.lean +++ b/Mathlib/Order/Bounds/Image.lean @@ -196,6 +196,45 @@ theorem map_isLeast : IsLeast s a → IsGreatest (f '' s) (f a) := end Antitone +section StrictMono + +variable [LinearOrder α] [Preorder β] {f : α → β} {a : α} {s : Set α} + +lemma StrictMono.mem_upperBounds_image (hf : StrictMono f) : + f a ∈ upperBounds (f '' s) ↔ a ∈ upperBounds s := by simp [upperBounds, hf.le_iff_le] + +lemma StrictMono.mem_lowerBounds_image (hf : StrictMono f) : + f a ∈ lowerBounds (f '' s) ↔ a ∈ lowerBounds s := by simp [lowerBounds, hf.le_iff_le] + +lemma StrictMono.map_isLeast (hf : StrictMono f) : IsLeast (f '' s) (f a) ↔ IsLeast s a := by + simp [IsLeast, hf.injective.eq_iff, hf.mem_lowerBounds_image] + +lemma StrictMono.map_isGreatest (hf : StrictMono f) : + IsGreatest (f '' s) (f a) ↔ IsGreatest s a := by + simp [IsGreatest, hf.injective.eq_iff, hf.mem_upperBounds_image] + +end StrictMono + +section StrictAnti + +variable [LinearOrder α] [Preorder β] {f : α → β} {a : α} {s : Set α} + +lemma StrictAnti.mem_upperBounds_image (hf : StrictAnti f) : + f a ∈ upperBounds (f '' s) ↔ a ∈ lowerBounds s := by + simp [upperBounds, lowerBounds, hf.le_iff_le] + +lemma StrictAnti.mem_lowerBounds_image (hf : StrictAnti f) : + f a ∈ lowerBounds (f '' s) ↔ a ∈ upperBounds s := by + simp [upperBounds, lowerBounds, hf.le_iff_le] + +lemma StrictAnti.map_isLeast (hf : StrictAnti f) : IsLeast (f '' s) (f a) ↔ IsGreatest s a := by + simp [IsLeast, IsGreatest, hf.injective.eq_iff, hf.mem_lowerBounds_image] + +lemma StrictAnti.map_isGreatest (hf : StrictAnti f) : IsGreatest (f '' s) (f a) ↔ IsLeast s a := by + simp [IsLeast, IsGreatest, hf.injective.eq_iff, hf.mem_upperBounds_image] + +end StrictAnti + section Image2 variable [Preorder α] [Preorder β] [Preorder γ] {f : α → β → γ} {s : Set α} {t : Set β} {a : α} @@ -209,11 +248,11 @@ include h₀ h₁ theorem mem_upperBounds_image2 (ha : a ∈ upperBounds s) (hb : b ∈ upperBounds t) : f a b ∈ upperBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem mem_lowerBounds_image2 (ha : a ∈ lowerBounds s) (hb : b ∈ lowerBounds t) : f a b ∈ lowerBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem image2_upperBounds_upperBounds_subset : image2 f (upperBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := @@ -253,11 +292,11 @@ include h₀ h₁ theorem mem_upperBounds_image2_of_mem_upperBounds_of_mem_lowerBounds (ha : a ∈ upperBounds s) (hb : b ∈ lowerBounds t) : f a b ∈ upperBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_upperBounds (ha : a ∈ lowerBounds s) (hb : b ∈ upperBounds t) : f a b ∈ lowerBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem image2_upperBounds_lowerBounds_subset_upperBounds_image2 : image2 f (upperBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := @@ -299,11 +338,11 @@ include h₀ h₁ theorem mem_upperBounds_image2_of_mem_lowerBounds (ha : a ∈ lowerBounds s) (hb : b ∈ lowerBounds t) : f a b ∈ upperBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem mem_lowerBounds_image2_of_mem_upperBounds (ha : a ∈ upperBounds s) (hb : b ∈ upperBounds t) : f a b ∈ lowerBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem image2_upperBounds_upperBounds_subset_upperBounds_image2 : image2 f (lowerBounds s) (lowerBounds t) ⊆ upperBounds (image2 f s t) := @@ -341,11 +380,11 @@ include h₀ h₁ theorem mem_upperBounds_image2_of_mem_upperBounds_of_mem_upperBounds (ha : a ∈ lowerBounds s) (hb : b ∈ upperBounds t) : f a b ∈ upperBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem mem_lowerBounds_image2_of_mem_lowerBounds_of_mem_lowerBounds (ha : a ∈ upperBounds s) (hb : b ∈ lowerBounds t) : f a b ∈ lowerBounds (image2 f s t) := - forall_image2_iff.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy + forall_mem_image2.2 fun _ hx _ hy => (h₀ _ <| ha hx).trans <| h₁ _ <| hb hy theorem image2_lowerBounds_upperBounds_subset_upperBounds_image2 : image2 f (lowerBounds s) (upperBounds t) ⊆ upperBounds (image2 f s t) := diff --git a/Mathlib/Order/Category/NonemptyFinLinOrd.lean b/Mathlib/Order/Category/NonemptyFinLinOrd.lean index 1bf3149bd7abe..ea21848f75410 100644 --- a/Mathlib/Order/Category/NonemptyFinLinOrd.lean +++ b/Mathlib/Order/Category/NonemptyFinLinOrd.lean @@ -178,7 +178,7 @@ theorem epi_iff_surjective {A B : NonemptyFinLinOrd.{u}} (f : A ⟶ B) : exact h₂ (le_of_lt h₁) · exfalso exact hm a (eq_of_le_of_not_lt h₂ h₁) - simp [Y, DFunLike.coe] at h + simp [Y, p₁, p₂, DFunLike.coe] at h · intro h exact ConcreteCategory.epi_of_surjective f h diff --git a/Mathlib/Order/Chain.lean b/Mathlib/Order/Chain.lean index f83b31886b200..dc6fc7aa7d720 100644 --- a/Mathlib/Order/Chain.lean +++ b/Mathlib/Order/Chain.lean @@ -52,10 +52,12 @@ def SuperChain (s t : Set α) : Prop := def IsMaxChain (s : Set α) : Prop := IsChain r s ∧ ∀ ⦃t⦄, IsChain r t → s ⊆ t → s = t -variable {r} {c c₁ c₂ s t : Set α} {a x y : α} +variable {r} {c c₁ c₂ s t : Set α} {a b x y : α} -theorem isChain_empty : IsChain r ∅ := - Set.pairwise_empty _ +@[simp] lemma IsChain.empty : IsChain r ∅ := pairwise_empty _ +@[simp] lemma IsChain.singleton : IsChain r {a} := pairwise_singleton .. + +@[deprecated (since := "2024-11-25")] alias isChain_empty := IsChain.empty theorem Set.Subsingleton.isChain (hs : s.Subsingleton) : IsChain r s := hs.pairwise _ @@ -78,6 +80,9 @@ protected theorem IsChain.insert (hs : IsChain r s) (ha : ∀ b ∈ s, a ≠ b IsChain r (insert a s) := hs.insert_of_symmetric (fun _ _ => Or.symm) ha +lemma IsChain.pair (h : r a b) : IsChain r {a, b} := + IsChain.singleton.insert fun _ hb _ ↦ .inl <| (eq_of_mem_singleton hb).symm.recOn ‹_› + theorem isChain_univ_iff : IsChain r (univ : Set α) ↔ IsTrichotomous α r := by refine ⟨fun h => ⟨fun a b => ?_⟩, fun h => @isChain_of_trichotomous _ _ h univ⟩ rw [or_left_comm, or_iff_not_imp_left] @@ -136,6 +141,14 @@ theorem IsMaxChain.bot_mem [LE α] [OrderBot α] (h : IsMaxChain (· ≤ ·) s) theorem IsMaxChain.top_mem [LE α] [OrderTop α] (h : IsMaxChain (· ≤ ·) s) : ⊤ ∈ s := (h.2 (h.1.insert fun _ _ _ => Or.inr le_top) <| subset_insert _ _).symm ▸ mem_insert _ _ +lemma IsMaxChain.image {s : β → β → Prop} (e : r ≃r s) {c : Set α} (hc : IsMaxChain r c) : + IsMaxChain s (e '' c) where + left := hc.isChain.image _ _ _ fun _ _ ↦ by exact e.map_rel_iff.2 + right t ht hf := by + rw [← e.coe_fn_toEquiv, ← e.toEquiv.eq_preimage_iff_image_eq, preimage_equiv_eq_image_symm] + exact hc.2 (ht.image _ _ _ fun _ _ ↦ by exact e.symm.map_rel_iff.2) + ((e.toEquiv.subset_symm_image _ _).2 hf) + open Classical in /-- Given a set `s`, if there exists a chain `t` strictly including `s`, then `SuccChain s` is one of these chains. Otherwise it is `s`. -/ @@ -302,11 +315,17 @@ theorem top_mem [OrderTop α] (s : Flag α) : (⊤ : α) ∈ s := theorem bot_mem [OrderBot α] (s : Flag α) : (⊥ : α) ∈ s := s.maxChain.bot_mem +/-- Reinterpret a maximal chain as a flag. -/ +def ofIsMaxChain (c : Set α) (hc : IsMaxChain (· ≤ ·) c) : Flag α := ⟨c, hc.isChain, hc.2⟩ + +@[simp, norm_cast] +lemma coe_ofIsMaxChain (c : Set α) (hc) : ofIsMaxChain c hc = c := rfl + end LE section Preorder -variable [Preorder α] {a b : α} +variable [Preorder α] [Preorder β] {a b : α} {s : Flag α} protected theorem le_or_le (s : Flag α) (ha : a ∈ s) (hb : b ∈ s) : a ≤ b ∨ b ≤ a := s.chain_le.total ha hb @@ -320,6 +339,24 @@ instance [OrderBot α] (s : Flag α) : OrderBot s := instance [BoundedOrder α] (s : Flag α) : BoundedOrder s := Subtype.boundedOrder s.bot_mem s.top_mem +lemma mem_iff_forall_le_or_ge : a ∈ s ↔ ∀ ⦃b⦄, b ∈ s → a ≤ b ∨ b ≤ a := + ⟨fun ha b => s.le_or_le ha, fun hb => + of_not_not fun ha => + Set.ne_insert_of_not_mem _ ‹_› <| + s.maxChain.2 (s.chain_le.insert fun c hc _ => hb hc) <| Set.subset_insert _ _⟩ + +/-- Flags are preserved under order isomorphisms. -/ +def map (e : α ≃o β) : Flag α ≃ Flag β + where + toFun s := ofIsMaxChain _ (s.maxChain.image e) + invFun s := ofIsMaxChain _ (s.maxChain.image e.symm) + left_inv s := ext <| e.symm_image_image s + right_inv s := ext <| e.image_symm_image s + +@[simp, norm_cast] lemma coe_map (e : α ≃o β) (s : Flag α) : ↑(map e s) = e '' s := rfl + +@[simp] lemma symm_map (e : α ≃o β) : (map e).symm = map e.symm := rfl + end Preorder section PartialOrder @@ -328,7 +365,7 @@ variable [PartialOrder α] theorem chain_lt (s : Flag α) : IsChain (· < ·) (s : Set α) := s.chain_le.lt_of_le -instance [@DecidableRel α (· ≤ ·)] [@DecidableRel α (· < ·)] (s : Flag α) : +instance [DecidableRel (α := α) (· ≤ ·)] [DecidableRel (α := α) (· < ·)] (s : Flag α) : LinearOrder s := { Subtype.partialOrder _ with le_total := fun a b => s.le_or_le a.2 b.2 diff --git a/Mathlib/Order/Cofinal.lean b/Mathlib/Order/Cofinal.lean index 572a4ffc3cedb..532481a8f4cbe 100644 --- a/Mathlib/Order/Cofinal.lean +++ b/Mathlib/Order/Cofinal.lean @@ -3,9 +3,7 @@ Copyright (c) 2024 Violeta Hernández Palacios. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Violeta Hernández Palacios -/ -import Mathlib.Data.Set.Basic -import Mathlib.Tactic.Contrapose -import Mathlib.Order.Bounds.Defs +import Mathlib.Order.GaloisConnection /-! # Cofinal sets @@ -21,7 +19,7 @@ For the cofinality of a set as a cardinal, see `Mathlib.SetTheory.Cardinal.Cofin - Deprecate `Order.Cofinal` in favor of this predicate. -/ -variable {α : Type*} +variable {α β : Type*} section LE variable [LE α] @@ -60,6 +58,16 @@ theorem IsCofinal.trans {s : Set α} {t : Set s} (hs : IsCofinal s) (ht : IsCofi obtain ⟨c, hc, hc'⟩ := ht ⟨b, hb⟩ exact ⟨c, Set.mem_image_of_mem _ hc, hb'.trans hc'⟩ +theorem GaloisConnection.map_cofinal [Preorder β] {f : β → α} {g : α → β} + (h : GaloisConnection f g) {s : Set α} (hs : IsCofinal s) : IsCofinal (g '' s) := by + intro a + obtain ⟨b, hb, hb'⟩ := hs (f a) + exact ⟨g b, Set.mem_image_of_mem _ hb, h.le_iff_le.1 hb'⟩ + +theorem OrderIso.map_cofinal [Preorder β] (e : α ≃o β) {s : Set α} (hs : IsCofinal s) : + IsCofinal (e '' s) := + e.symm.to_galoisConnection.map_cofinal hs + end Preorder section PartialOrder @@ -105,4 +113,14 @@ theorem not_isCofinal_iff_bddAbove [NoMaxOrder α] {s : Set α} : ¬ IsCofinal s theorem not_bddAbove_iff_isCofinal [NoMaxOrder α] {s : Set α} : ¬ BddAbove s ↔ IsCofinal s := not_iff_comm.1 not_isCofinal_iff_bddAbove +/-- The set of "records" (the smallest inputs yielding the highest values) with respect to a +well-ordering of `α` is a cofinal set. -/ +theorem isCofinal_setOf_imp_lt (r : α → α → Prop) [h : IsWellFounded α r] : + IsCofinal { a | ∀ b, r b a → b < a } := by + intro a + obtain ⟨b, hb, hb'⟩ := h.wf.has_min (Set.Ici a) Set.nonempty_Ici + refine ⟨b, fun c hc ↦ ?_, hb⟩ + by_contra! hc' + exact hb' c (hb.trans hc') hc + end LinearOrder diff --git a/Mathlib/Order/Compare.lean b/Mathlib/Order/Compare.lean index 5e29b6e29a069..763fb3ead16a0 100644 --- a/Mathlib/Order/Compare.lean +++ b/Mathlib/Order/Compare.lean @@ -25,16 +25,16 @@ variable {α β : Type*} /-- Like `cmp`, but uses a `≤` on the type instead of `<`. Given two elements `x` and `y`, returns a three-way comparison result `Ordering`. -/ -def cmpLE {α} [LE α] [@DecidableRel α (· ≤ ·)] (x y : α) : Ordering := +def cmpLE {α} [LE α] [DecidableRel (α := α) (· ≤ ·)] (x y : α) : Ordering := if x ≤ y then if y ≤ x then Ordering.eq else Ordering.lt else Ordering.gt -theorem cmpLE_swap {α} [LE α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x y : α) : +theorem cmpLE_swap {α} [LE α] [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] (x y : α) : (cmpLE x y).swap = cmpLE y x := by by_cases xy : x ≤ y <;> by_cases yx : y ≤ x <;> simp [cmpLE, *, Ordering.swap] cases not_or_intro xy yx (total_of _ _ _) -theorem cmpLE_eq_cmp {α} [Preorder α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] - [@DecidableRel α (· < ·)] (x y : α) : cmpLE x y = cmp x y := by +theorem cmpLE_eq_cmp {α} [Preorder α] [IsTotal α (· ≤ ·)] [DecidableRel (α := α) (· ≤ ·)] + [DecidableRel (α := α) (· < ·)] (x y : α) : cmpLE x y = cmp x y := by by_cases xy : x ≤ y <;> by_cases yx : y ≤ x <;> simp [cmpLE, lt_iff_le_not_le, *, cmp, cmpUsing] cases not_or_intro xy yx (total_of _ _ _) @@ -132,28 +132,29 @@ theorem Ordering.Compares.cmp_eq [LinearOrder α] {a b : α} {o : Ordering} (h : (cmp_compares a b).inj h @[simp] -theorem cmp_swap [Preorder α] [@DecidableRel α (· < ·)] (a b : α) : (cmp a b).swap = cmp b a := by +theorem cmp_swap [Preorder α] [DecidableRel (α := α) (· < ·)] (a b : α) : + (cmp a b).swap = cmp b a := by unfold cmp cmpUsing by_cases h : a < b <;> by_cases h₂ : b < a <;> simp [h, h₂, Ordering.swap] exact lt_asymm h h₂ @[simp] -theorem cmpLE_toDual [LE α] [@DecidableRel α (· ≤ ·)] (x y : α) : +theorem cmpLE_toDual [LE α] [DecidableRel (α := α) (· ≤ ·)] (x y : α) : cmpLE (toDual x) (toDual y) = cmpLE y x := rfl @[simp] -theorem cmpLE_ofDual [LE α] [@DecidableRel α (· ≤ ·)] (x y : αᵒᵈ) : +theorem cmpLE_ofDual [LE α] [DecidableRel (α := α) (· ≤ ·)] (x y : αᵒᵈ) : cmpLE (ofDual x) (ofDual y) = cmpLE y x := rfl @[simp] -theorem cmp_toDual [LT α] [@DecidableRel α (· < ·)] (x y : α) : +theorem cmp_toDual [LT α] [DecidableRel (α := α) (· < ·)] (x y : α) : cmp (toDual x) (toDual y) = cmp y x := rfl @[simp] -theorem cmp_ofDual [LT α] [@DecidableRel α (· < ·)] (x y : αᵒᵈ) : +theorem cmp_ofDual [LT α] [DecidableRel (α := α) (· < ·)] (x y : αᵒᵈ) : cmp (ofDual x) (ofDual y) = cmp y x := rfl diff --git a/Mathlib/Order/CompleteLattice/Finset.lean b/Mathlib/Order/CompleteLattice/Finset.lean index b02e5eb918efa..b3607813b1f92 100644 --- a/Mathlib/Order/CompleteLattice/Finset.lean +++ b/Mathlib/Order/CompleteLattice/Finset.lean @@ -11,7 +11,8 @@ import Mathlib.Data.Set.Lattice This file is concerned with how big lattice or set operations behave when indexed by a finset. -See also Lattice.lean, which is concerned with folding binary lattice operations over a finset. +See also `Mathlib/Data/Finset/Lattice.lean`, which is concerned with folding binary lattice +operations over a finset. -/ assert_not_exists OrderedCommMonoid diff --git a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean index 437a1e3d52e13..0773cfe1e11e4 100644 --- a/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean +++ b/Mathlib/Order/ConditionallyCompleteLattice/Basic.lean @@ -809,7 +809,7 @@ theorem csSup_image2_eq_csSup_csSup (h₁ : ∀ b, GaloisConnection (swap l b) ( refine eq_of_forall_ge_iff fun c => ?_ rw [csSup_le_iff (hs₁.image2 (fun _ => (h₁ _).monotone_l) (fun _ => (h₂ _).monotone_l) ht₁) (hs₀.image2 ht₀), - forall_image2_iff, forall₂_swap, (h₂ _).le_iff_le, csSup_le_iff ht₁ ht₀] + forall_mem_image2, forall₂_swap, (h₂ _).le_iff_le, csSup_le_iff ht₁ ht₀] simp_rw [← (h₂ _).le_iff_le, (h₁ _).le_iff_le, csSup_le_iff hs₁ hs₀] theorem csSup_image2_eq_csSup_csInf (h₁ : ∀ b, GaloisConnection (swap l b) (u₁ b)) diff --git a/Mathlib/Order/CountableDenseLinearOrder.lean b/Mathlib/Order/CountableDenseLinearOrder.lean index 52b1a34e4be76..31a60023ff36c 100644 --- a/Mathlib/Order/CountableDenseLinearOrder.lean +++ b/Mathlib/Order/CountableDenseLinearOrder.lean @@ -170,7 +170,7 @@ variable (β) def definedAtLeft [DenselyOrdered β] [NoMinOrder β] [NoMaxOrder β] [Nonempty β] (a : α) : Cofinal (PartialIso α β) where carrier := {f | ∃ b : β, (a, b) ∈ f.val} - mem_gt f := by + isCofinal f := by cases' exists_across f a with b a_b refine ⟨⟨insert (a, b) f.val, fun p hp q hq ↦ ?_⟩, ⟨b, Finset.mem_insert_self _ _⟩, @@ -190,8 +190,8 @@ variable (α) {β} def definedAtRight [DenselyOrdered α] [NoMinOrder α] [NoMaxOrder α] [Nonempty α] (b : β) : Cofinal (PartialIso α β) where carrier := {f | ∃ a, (a, b) ∈ f.val} - mem_gt f := by - rcases (definedAtLeft α b).mem_gt f.comm with ⟨f', ⟨a, ha⟩, hl⟩ + isCofinal f := by + rcases (definedAtLeft α b).isCofinal f.comm with ⟨f', ⟨a, ha⟩, hl⟩ refine ⟨f'.comm, ⟨a, ?_⟩, ?_⟩ · change (a, b) ∈ f'.val.image _ rwa [← Finset.mem_coe, Finset.coe_image, Equiv.image_eq_preimage] diff --git a/Mathlib/Order/Defs/PartialOrder.lean b/Mathlib/Order/Defs/PartialOrder.lean index 377677f6d9855..d5bac42a0abd8 100644 --- a/Mathlib/Order/Defs/PartialOrder.lean +++ b/Mathlib/Order/Defs/PartialOrder.lean @@ -97,7 +97,7 @@ instance (priority := 900) : @Trans α α α GT.gt GE.ge GT.gt := ⟨gt_of_gt_of instance (priority := 900) : @Trans α α α GE.ge GT.gt GT.gt := ⟨gt_of_ge_of_gt⟩ /-- `<` is decidable if `≤` is. -/ -def decidableLTOfDecidableLE [@DecidableRel α (· ≤ ·)] : @DecidableRel α (· < ·) +def decidableLTOfDecidableLE [DecidableRel (α := α) (· ≤ ·)] : DecidableRel (α := α) (· < ·) | a, b => if hab : a ≤ b then if hba : b ≤ a then isFalse fun hab' => not_le_of_gt hab' hba @@ -129,7 +129,7 @@ lemma lt_of_le_of_ne : a ≤ b → a ≠ b → a < b := fun h₁ h₂ => lt_of_le_not_le h₁ <| mt (le_antisymm h₁) h₂ /-- Equality is decidable if `≤` is. -/ -def decidableEqOfDecidableLE [@DecidableRel α (· ≤ ·)] : DecidableEq α +def decidableEqOfDecidableLE [DecidableRel (α := α) (· ≤ ·)] : DecidableEq α | a, b => if hab : a ≤ b then if hba : b ≤ a then isTrue (le_antisymm hab hba) else isFalse fun heq => hba (heq ▸ le_refl _) @@ -137,7 +137,7 @@ def decidableEqOfDecidableLE [@DecidableRel α (· ≤ ·)] : DecidableEq α namespace Decidable -variable [@DecidableRel α (· ≤ ·)] +variable [DecidableRel (α := α) (· ≤ ·)] lemma lt_or_eq_of_le (hab : a ≤ b) : a < b ∨ a = b := if hba : b ≤ a then Or.inr (le_antisymm hab hba) else Or.inl (lt_of_le_not_le hab hba) diff --git a/Mathlib/Order/Extension/Well.lean b/Mathlib/Order/Extension/Well.lean index 1b5175e593d0c..3d74ec49658eb 100644 --- a/Mathlib/Order/Extension/Well.lean +++ b/Mathlib/Order/Extension/Well.lean @@ -70,10 +70,9 @@ end IsWellFounded namespace WellFounded -set_option linter.deprecated false - variable (hwf : WellFounded r) +set_option linter.deprecated false in /-- An arbitrary well order on `α` that extends `r`. The construction maps `r` into two well-orders: the first map is `WellFounded.rank`, which is not @@ -89,12 +88,14 @@ noncomputable def wellOrderExtension : LinearOrder α := @LinearOrder.lift' α (Ordinal ×ₗ Cardinal) _ (fun a : α => (hwf.rank a, embeddingToCardinal a)) fun _ _ h => embeddingToCardinal.injective <| congr_arg Prod.snd h +set_option linter.deprecated false in @[deprecated IsWellFounded.wellOrderExtension.isWellFounded_lt (since := "2024-09-07")] instance wellOrderExtension.isWellFounded_lt : IsWellFounded α hwf.wellOrderExtension.lt := ⟨InvImage.wf (fun a : α => (hwf.rank a, embeddingToCardinal a)) <| Ordinal.lt_wf.prod_lex Cardinal.lt_wf⟩ include hwf in +set_option linter.deprecated false in /-- Any well-founded relation can be extended to a well-ordering on that type. -/ @[deprecated IsWellFounded.exists_well_order_ge (since := "2024-09-07")] theorem exists_well_order_ge : ∃ s, r ≤ s ∧ IsWellOrder α s := diff --git a/Mathlib/Order/Filter/AtTopBot.lean b/Mathlib/Order/Filter/AtTopBot.lean index ed602722331c0..d8c1fe0ab97b7 100644 --- a/Mathlib/Order/Filter/AtTopBot.lean +++ b/Mathlib/Order/Filter/AtTopBot.lean @@ -172,20 +172,6 @@ theorem Tendsto.eventually_forall_le_atBot [Preorder β] {l : Filter α} ∀ᶠ x in l, ∀ y, y ≤ f x → p y := by rw [← Filter.eventually_forall_le_atBot] at h_evtl; exact (h_evtl.comap f).filter_mono hf.le_comap -instance (priority := 200) atTop.isCountablyGenerated [Preorder α] [Countable α] : - (atTop : Filter <| α).IsCountablyGenerated := - isCountablyGenerated_seq _ - -instance (priority := 200) atBot.isCountablyGenerated [Preorder α] [Countable α] : - (atBot : Filter <| α).IsCountablyGenerated := - isCountablyGenerated_seq _ - -instance _root_.OrderDual.instIsCountablyGeneratedAtTop [Preorder α] - [IsCountablyGenerated (atBot : Filter α)] : IsCountablyGenerated (atTop : Filter αᵒᵈ) := ‹_› - -instance _root_.OrderDual.instIsCountablyGeneratedAtBot [Preorder α] - [IsCountablyGenerated (atTop : Filter α)] : IsCountablyGenerated (atBot : Filter αᵒᵈ) := ‹_› - theorem _root_.IsTop.atTop_eq [Preorder α] {a : α} (ha : IsTop a) : atTop = 𝓟 (Ici a) := (iInf_le _ _).antisymm <| le_iInf fun b ↦ principal_mono.2 <| Ici_subset_Ici.2 <| ha b @@ -291,10 +277,6 @@ theorem map_atTop_eq {f : α → β} : atTop.map f = ⨅ a, 𝓟 (f '' { a' | a theorem frequently_atTop' [NoMaxOrder α] : (∃ᶠ x in atTop, p x) ↔ ∀ a, ∃ b > a, p b := atTop_basis_Ioi.frequently_iff.trans <| by simp -lemma atTop_countable_basis [Countable α] : - HasCountableBasis (atTop : Filter α) (fun _ => True) Ici := - { atTop_basis with countable := to_countable _ } - end IsDirected section IsCodirected @@ -333,10 +315,6 @@ theorem map_atBot_eq {f : α → β} : atBot.map f = ⨅ a, 𝓟 (f '' { a' | a' theorem frequently_atBot' [NoMinOrder α] : (∃ᶠ x in atBot, p x) ↔ ∀ a, ∃ b < a, p b := frequently_atTop' (α := αᵒᵈ) -lemma atBot_countable_basis [Countable α] : - HasCountableBasis (atBot : Filter α) (fun _ => True) Iic := - { atBot_basis with countable := to_countable _ } - end IsCodirected theorem tendsto_atTop [Preorder β] {m : α → β} {f : Filter α} : @@ -918,12 +896,6 @@ theorem prod_atTop_atTop_eq [Preorder α] [Preorder β] : · subsingleton simpa [atTop, prod_iInf_left, prod_iInf_right, iInf_prod] using iInf_comm -instance instIsCountablyGeneratedAtTopProd [Preorder α] [IsCountablyGenerated (atTop : Filter α)] - [Preorder β] [IsCountablyGenerated (atTop : Filter β)] : - IsCountablyGenerated (atTop : Filter (α × β)) := by - rw [← prod_atTop_atTop_eq] - infer_instance - lemma tendsto_finset_prod_atTop : Tendsto (fun (p : Finset ι × Finset ι') ↦ p.1 ×ˢ p.2) atTop atTop := by classical @@ -938,12 +910,6 @@ theorem prod_atBot_atBot_eq [Preorder α] [Preorder β] : (atBot : Filter α) ×ˢ (atBot : Filter β) = (atBot : Filter (α × β)) := @prod_atTop_atTop_eq αᵒᵈ βᵒᵈ _ _ -instance instIsCountablyGeneratedAtBotProd [Preorder α] [IsCountablyGenerated (atBot : Filter α)] - [Preorder β] [IsCountablyGenerated (atBot : Filter β)] : - IsCountablyGenerated (atBot : Filter (α × β)) := by - rw [← prod_atBot_atBot_eq] - infer_instance - theorem prod_map_atTop_eq {α₁ α₂ β₁ β₂ : Type*} [Preorder β₁] [Preorder β₂] (u₁ : β₁ → α₁) (u₂ : β₂ → α₂) : map u₁ atTop ×ˢ map u₂ atTop = map (Prod.map u₁ u₂) atTop := by rw [prod_map_map_eq, prod_atTop_atTop_eq, Prod.map_def] @@ -1296,106 +1262,12 @@ theorem HasAntitoneBasis.subbasis_with_rel {f : Filter α} {s : ℕ → Set α} simp only [forall_mem_image, forall_and, mem_Iio] at hφ exact ⟨φ, forall_swap.2 hφ.1, forall_swap.2 hφ.2⟩ -/-- If `f` is a nontrivial countably generated filter, then there exists a sequence that converges -to `f`. -/ -theorem exists_seq_tendsto (f : Filter α) [IsCountablyGenerated f] [NeBot f] : - ∃ x : ℕ → α, Tendsto x atTop f := by - obtain ⟨B, h⟩ := f.exists_antitone_basis - choose x hx using fun n => Filter.nonempty_of_mem (h.mem n) - exact ⟨x, h.tendsto hx⟩ - -theorem exists_seq_monotone_tendsto_atTop_atTop (α : Type*) [Preorder α] [Nonempty α] - [IsDirected α (· ≤ ·)] [(atTop : Filter α).IsCountablyGenerated] : - ∃ xs : ℕ → α, Monotone xs ∧ Tendsto xs atTop atTop := by - obtain ⟨ys, h⟩ := exists_seq_tendsto (atTop : Filter α) - choose c hleft hright using exists_ge_ge (α := α) - set xs : ℕ → α := fun n => (List.range n).foldl (fun x n ↦ c x (ys n)) (ys 0) - have hsucc (n : ℕ) : xs (n + 1) = c (xs n) (ys n) := by simp [xs, List.range_succ] - refine ⟨xs, ?_, ?_⟩ - · refine monotone_nat_of_le_succ fun n ↦ ?_ - rw [hsucc] - apply hleft - · refine (tendsto_add_atTop_iff_nat 1).1 <| tendsto_atTop_mono (fun n ↦ ?_) h - rw [hsucc] - apply hright - -theorem exists_seq_antitone_tendsto_atTop_atBot (α : Type*) [Preorder α] [Nonempty α] - [IsDirected α (· ≥ ·)] [(atBot : Filter α).IsCountablyGenerated] : - ∃ xs : ℕ → α, Antitone xs ∧ Tendsto xs atTop atBot := - exists_seq_monotone_tendsto_atTop_atTop αᵒᵈ - -/-- An abstract version of continuity of sequentially continuous functions on metric spaces: -if a filter `k` is countably generated then `Tendsto f k l` iff for every sequence `u` -converging to `k`, `f ∘ u` tends to `l`. -/ -theorem tendsto_iff_seq_tendsto {f : α → β} {k : Filter α} {l : Filter β} [k.IsCountablyGenerated] : - Tendsto f k l ↔ ∀ x : ℕ → α, Tendsto x atTop k → Tendsto (f ∘ x) atTop l := by - refine ⟨fun h x hx => h.comp hx, fun H s hs => ?_⟩ - contrapose! H - have : NeBot (k ⊓ 𝓟 (f ⁻¹' sᶜ)) := by simpa [neBot_iff, inf_principal_eq_bot] - rcases (k ⊓ 𝓟 (f ⁻¹' sᶜ)).exists_seq_tendsto with ⟨x, hx⟩ - rw [tendsto_inf, tendsto_principal] at hx - refine ⟨x, hx.1, fun h => ?_⟩ - rcases (hx.2.and (h hs)).exists with ⟨N, hnmem, hmem⟩ - exact hnmem hmem - -theorem tendsto_of_seq_tendsto {f : α → β} {k : Filter α} {l : Filter β} [k.IsCountablyGenerated] : - (∀ x : ℕ → α, Tendsto x atTop k → Tendsto (f ∘ x) atTop l) → Tendsto f k l := - tendsto_iff_seq_tendsto.2 - -theorem eventually_iff_seq_eventually {ι : Type*} {l : Filter ι} {p : ι → Prop} - [l.IsCountablyGenerated] : - (∀ᶠ n in l, p n) ↔ ∀ x : ℕ → ι, Tendsto x atTop l → ∀ᶠ n : ℕ in atTop, p (x n) := by - simpa using tendsto_iff_seq_tendsto (f := id) (l := 𝓟 {x | p x}) - -theorem frequently_iff_seq_frequently {ι : Type*} {l : Filter ι} {p : ι → Prop} - [l.IsCountablyGenerated] : - (∃ᶠ n in l, p n) ↔ ∃ x : ℕ → ι, Tendsto x atTop l ∧ ∃ᶠ n : ℕ in atTop, p (x n) := by - simp only [Filter.Frequently, eventually_iff_seq_eventually (l := l)] - push_neg; rfl - theorem subseq_forall_of_frequently {ι : Type*} {x : ℕ → ι} {p : ι → Prop} {l : Filter ι} (h_tendsto : Tendsto x atTop l) (h : ∃ᶠ n in atTop, p (x n)) : ∃ ns : ℕ → ℕ, Tendsto (fun n => x (ns n)) atTop l ∧ ∀ n, p (x (ns n)) := by choose ns hge hns using frequently_atTop.1 h exact ⟨ns, h_tendsto.comp (tendsto_atTop_mono hge tendsto_id), hns⟩ -theorem exists_seq_forall_of_frequently {ι : Type*} {l : Filter ι} {p : ι → Prop} - [l.IsCountablyGenerated] (h : ∃ᶠ n in l, p n) : - ∃ ns : ℕ → ι, Tendsto ns atTop l ∧ ∀ n, p (ns n) := by - rw [frequently_iff_seq_frequently] at h - obtain ⟨x, hx_tendsto, hx_freq⟩ := h - obtain ⟨n_to_n, h_tendsto, h_freq⟩ := subseq_forall_of_frequently hx_tendsto hx_freq - exact ⟨x ∘ n_to_n, h_tendsto, h_freq⟩ - -lemma frequently_iff_seq_forall {ι : Type*} {l : Filter ι} {p : ι → Prop} - [l.IsCountablyGenerated] : - (∃ᶠ n in l, p n) ↔ ∃ ns : ℕ → ι, Tendsto ns atTop l ∧ ∀ n, p (ns n) := - ⟨exists_seq_forall_of_frequently, fun ⟨_ns, hnsl, hpns⟩ ↦ - hnsl.frequently <| Frequently.of_forall hpns⟩ - -/-- A sequence converges if every subsequence has a convergent subsequence. -/ -theorem tendsto_of_subseq_tendsto {ι : Type*} {x : ι → α} {f : Filter α} {l : Filter ι} - [l.IsCountablyGenerated] - (hxy : ∀ ns : ℕ → ι, Tendsto ns atTop l → - ∃ ms : ℕ → ℕ, Tendsto (fun n => x (ns <| ms n)) atTop f) : - Tendsto x l f := by - contrapose! hxy - obtain ⟨s, hs, hfreq⟩ : ∃ s ∈ f, ∃ᶠ n in l, x n ∉ s := by - rwa [not_tendsto_iff_exists_frequently_nmem] at hxy - obtain ⟨y, hy_tendsto, hy_freq⟩ := exists_seq_forall_of_frequently hfreq - refine ⟨y, hy_tendsto, fun ms hms_tendsto ↦ ?_⟩ - rcases (hms_tendsto.eventually_mem hs).exists with ⟨n, hn⟩ - exact absurd hn <| hy_freq _ - -theorem subseq_tendsto_of_neBot {f : Filter α} [IsCountablyGenerated f] {u : ℕ → α} - (hx : NeBot (f ⊓ map u atTop)) : ∃ θ : ℕ → ℕ, StrictMono θ ∧ Tendsto (u ∘ θ) atTop f := by - rw [← Filter.push_pull', map_neBot_iff] at hx - rcases exists_seq_tendsto (comap u f ⊓ atTop) with ⟨φ, hφ⟩ - rw [tendsto_inf, tendsto_comap_iff] at hφ - obtain ⟨ψ, hψ, hψφ⟩ : ∃ ψ : ℕ → ℕ, StrictMono ψ ∧ StrictMono (φ ∘ ψ) := - strictMono_subseq_of_tendsto_atTop hφ.2 - exact ⟨φ ∘ ψ, hψφ, hφ.1.comp hψ.tendsto_atTop⟩ - end Filter open Filter Finset diff --git a/Mathlib/Order/Filter/AtTopBot/Archimedean.lean b/Mathlib/Order/Filter/AtTopBot/Archimedean.lean index ecc8b33a34a1d..167f93687a47d 100644 --- a/Mathlib/Order/Filter/AtTopBot/Archimedean.lean +++ b/Mathlib/Order/Filter/AtTopBot/Archimedean.lean @@ -5,6 +5,7 @@ Authors: Johannes Hölzl, Yury Kudryashov -/ import Mathlib.Algebra.Order.Archimedean.Basic import Mathlib.Order.Filter.AtTopBot.Group +import Mathlib.Order.Filter.CountablyGenerated import Mathlib.Tactic.GCongr /-! diff --git a/Mathlib/Order/Filter/AtTopBot/CountablyGenerated.lean b/Mathlib/Order/Filter/AtTopBot/CountablyGenerated.lean new file mode 100644 index 0000000000000..96978e899bf72 --- /dev/null +++ b/Mathlib/Order/Filter/AtTopBot/CountablyGenerated.lean @@ -0,0 +1,155 @@ +/- +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, Jeremy Avigad, Yury Kudryashov, Patrick Massot +-/ +import Mathlib.Order.Filter.AtTopBot +import Mathlib.Order.Filter.CountablyGenerated + +/-! +# Convergence to infinity and countably generated filters + +In this file we prove that + +- `Filter.atTop` and `Filter.atBot` filters on a countable type are countably generated; +- `Filter.exists_seq_tendsto`: if `f` is a nontrivial countably generated filter, + then there exists a sequence that converges. to `f`; +- `Filter.tendsto_iff_seq_tendsto`: convergence along a countably generated filter + is equivalent to convergence along all sequences that converge to this filter. +-/ + +open Set + +namespace Filter + +variable {α β : Type*} + +instance (priority := 200) atTop.isCountablyGenerated [Preorder α] [Countable α] : + (atTop : Filter <| α).IsCountablyGenerated := + isCountablyGenerated_seq _ + +instance (priority := 200) atBot.isCountablyGenerated [Preorder α] [Countable α] : + (atBot : Filter <| α).IsCountablyGenerated := + isCountablyGenerated_seq _ + +instance instIsCountablyGeneratedAtTopProd [Preorder α] [IsCountablyGenerated (atTop : Filter α)] + [Preorder β] [IsCountablyGenerated (atTop : Filter β)] : + IsCountablyGenerated (atTop : Filter (α × β)) := by + rw [← prod_atTop_atTop_eq] + infer_instance + +instance instIsCountablyGeneratedAtBotProd [Preorder α] [IsCountablyGenerated (atBot : Filter α)] + [Preorder β] [IsCountablyGenerated (atBot : Filter β)] : + IsCountablyGenerated (atBot : Filter (α × β)) := by + rw [← prod_atBot_atBot_eq] + infer_instance + +instance _root_.OrderDual.instIsCountablyGeneratedAtTop [Preorder α] + [IsCountablyGenerated (atBot : Filter α)] : IsCountablyGenerated (atTop : Filter αᵒᵈ) := ‹_› + +instance _root_.OrderDual.instIsCountablyGeneratedAtBot [Preorder α] + [IsCountablyGenerated (atTop : Filter α)] : IsCountablyGenerated (atBot : Filter αᵒᵈ) := ‹_› + +lemma atTop_countable_basis [Preorder α] [IsDirected α (· ≤ ·)] [Nonempty α] [Countable α] : + HasCountableBasis (atTop : Filter α) (fun _ => True) Ici := + { atTop_basis with countable := to_countable _ } + +lemma atBot_countable_basis [Preorder α] [IsDirected α (· ≥ ·)] [Nonempty α] [Countable α] : + HasCountableBasis (atBot : Filter α) (fun _ => True) Iic := + { atBot_basis with countable := to_countable _ } + +/-- If `f` is a nontrivial countably generated filter, then there exists a sequence that converges +to `f`. -/ +theorem exists_seq_tendsto (f : Filter α) [IsCountablyGenerated f] [NeBot f] : + ∃ x : ℕ → α, Tendsto x atTop f := by + obtain ⟨B, h⟩ := f.exists_antitone_basis + choose x hx using fun n => Filter.nonempty_of_mem (h.mem n) + exact ⟨x, h.tendsto hx⟩ + +theorem exists_seq_monotone_tendsto_atTop_atTop (α : Type*) [Preorder α] [Nonempty α] + [IsDirected α (· ≤ ·)] [(atTop : Filter α).IsCountablyGenerated] : + ∃ xs : ℕ → α, Monotone xs ∧ Tendsto xs atTop atTop := by + obtain ⟨ys, h⟩ := exists_seq_tendsto (atTop : Filter α) + choose c hleft hright using exists_ge_ge (α := α) + set xs : ℕ → α := fun n => (List.range n).foldl (fun x n ↦ c x (ys n)) (ys 0) + have hsucc (n : ℕ) : xs (n + 1) = c (xs n) (ys n) := by simp [xs, List.range_succ] + refine ⟨xs, ?_, ?_⟩ + · refine monotone_nat_of_le_succ fun n ↦ ?_ + rw [hsucc] + apply hleft + · refine (tendsto_add_atTop_iff_nat 1).1 <| tendsto_atTop_mono (fun n ↦ ?_) h + rw [hsucc] + apply hright + +theorem exists_seq_antitone_tendsto_atTop_atBot (α : Type*) [Preorder α] [Nonempty α] + [IsDirected α (· ≥ ·)] [(atBot : Filter α).IsCountablyGenerated] : + ∃ xs : ℕ → α, Antitone xs ∧ Tendsto xs atTop atBot := + exists_seq_monotone_tendsto_atTop_atTop αᵒᵈ + +/-- An abstract version of continuity of sequentially continuous functions on metric spaces: +if a filter `k` is countably generated then `Tendsto f k l` iff for every sequence `u` +converging to `k`, `f ∘ u` tends to `l`. -/ +theorem tendsto_iff_seq_tendsto {f : α → β} {k : Filter α} {l : Filter β} [k.IsCountablyGenerated] : + Tendsto f k l ↔ ∀ x : ℕ → α, Tendsto x atTop k → Tendsto (f ∘ x) atTop l := by + refine ⟨fun h x hx => h.comp hx, fun H s hs => ?_⟩ + contrapose! H + have : NeBot (k ⊓ 𝓟 (f ⁻¹' sᶜ)) := by simpa [neBot_iff, inf_principal_eq_bot] + rcases (k ⊓ 𝓟 (f ⁻¹' sᶜ)).exists_seq_tendsto with ⟨x, hx⟩ + rw [tendsto_inf, tendsto_principal] at hx + refine ⟨x, hx.1, fun h => ?_⟩ + rcases (hx.2.and (h hs)).exists with ⟨N, hnmem, hmem⟩ + exact hnmem hmem + +theorem tendsto_of_seq_tendsto {f : α → β} {k : Filter α} {l : Filter β} [k.IsCountablyGenerated] : + (∀ x : ℕ → α, Tendsto x atTop k → Tendsto (f ∘ x) atTop l) → Tendsto f k l := + tendsto_iff_seq_tendsto.2 + +theorem eventually_iff_seq_eventually {ι : Type*} {l : Filter ι} {p : ι → Prop} + [l.IsCountablyGenerated] : + (∀ᶠ n in l, p n) ↔ ∀ x : ℕ → ι, Tendsto x atTop l → ∀ᶠ n : ℕ in atTop, p (x n) := by + simpa using tendsto_iff_seq_tendsto (f := id) (l := 𝓟 {x | p x}) + +theorem frequently_iff_seq_frequently {ι : Type*} {l : Filter ι} {p : ι → Prop} + [l.IsCountablyGenerated] : + (∃ᶠ n in l, p n) ↔ ∃ x : ℕ → ι, Tendsto x atTop l ∧ ∃ᶠ n : ℕ in atTop, p (x n) := by + simp only [Filter.Frequently, eventually_iff_seq_eventually (l := l)] + push_neg; rfl + +theorem exists_seq_forall_of_frequently {ι : Type*} {l : Filter ι} {p : ι → Prop} + [l.IsCountablyGenerated] (h : ∃ᶠ n in l, p n) : + ∃ ns : ℕ → ι, Tendsto ns atTop l ∧ ∀ n, p (ns n) := by + rw [frequently_iff_seq_frequently] at h + obtain ⟨x, hx_tendsto, hx_freq⟩ := h + obtain ⟨n_to_n, h_tendsto, h_freq⟩ := subseq_forall_of_frequently hx_tendsto hx_freq + exact ⟨x ∘ n_to_n, h_tendsto, h_freq⟩ + +lemma frequently_iff_seq_forall {ι : Type*} {l : Filter ι} {p : ι → Prop} + [l.IsCountablyGenerated] : + (∃ᶠ n in l, p n) ↔ ∃ ns : ℕ → ι, Tendsto ns atTop l ∧ ∀ n, p (ns n) := + ⟨exists_seq_forall_of_frequently, fun ⟨_ns, hnsl, hpns⟩ ↦ + hnsl.frequently <| Frequently.of_forall hpns⟩ + +/-- A sequence converges if every subsequence has a convergent subsequence. -/ +theorem tendsto_of_subseq_tendsto {ι : Type*} {x : ι → α} {f : Filter α} {l : Filter ι} + [l.IsCountablyGenerated] + (hxy : ∀ ns : ℕ → ι, Tendsto ns atTop l → + ∃ ms : ℕ → ℕ, Tendsto (fun n => x (ns <| ms n)) atTop f) : + Tendsto x l f := by + contrapose! hxy + obtain ⟨s, hs, hfreq⟩ : ∃ s ∈ f, ∃ᶠ n in l, x n ∉ s := by + rwa [not_tendsto_iff_exists_frequently_nmem] at hxy + obtain ⟨y, hy_tendsto, hy_freq⟩ := exists_seq_forall_of_frequently hfreq + refine ⟨y, hy_tendsto, fun ms hms_tendsto ↦ ?_⟩ + rcases (hms_tendsto.eventually_mem hs).exists with ⟨n, hn⟩ + exact absurd hn <| hy_freq _ + +theorem subseq_tendsto_of_neBot {f : Filter α} [IsCountablyGenerated f] {u : ℕ → α} + (hx : NeBot (f ⊓ map u atTop)) : ∃ θ : ℕ → ℕ, StrictMono θ ∧ Tendsto (u ∘ θ) atTop f := by + rw [← Filter.push_pull', map_neBot_iff] at hx + rcases exists_seq_tendsto (comap u f ⊓ atTop) with ⟨φ, hφ⟩ + rw [tendsto_inf, tendsto_comap_iff] at hφ + obtain ⟨ψ, hψ, hψφ⟩ : ∃ ψ : ℕ → ℕ, StrictMono ψ ∧ StrictMono (φ ∘ ψ) := + strictMono_subseq_of_tendsto_atTop hφ.2 + exact ⟨φ ∘ ψ, hψφ, hφ.1.comp hψ.tendsto_atTop⟩ + +end Filter diff --git a/Mathlib/Order/Filter/AtTopBot/Field.lean b/Mathlib/Order/Filter/AtTopBot/Field.lean index 519009d383724..1112b9f9d9e92 100644 --- a/Mathlib/Order/Filter/AtTopBot/Field.lean +++ b/Mathlib/Order/Filter/AtTopBot/Field.lean @@ -94,7 +94,7 @@ theorem tendsto_const_mul_pow_atTop_iff : exact pos_of_mul_pos_left hck (pow_nonneg hk _) lemma tendsto_zpow_atTop_atTop {n : ℤ} (hn : 0 < n) : Tendsto (fun x : α ↦ x ^ n) atTop atTop := by - lift n to ℕ+ using hn; simp + lift n to ℕ using hn.le; simp [(Int.ofNat_pos.mp hn).ne'] end LinearOrderedSemifield diff --git a/Mathlib/Order/Filter/Bases.lean b/Mathlib/Order/Filter/Bases.lean index ab8dd13872eb6..42dfb3d129084 100644 --- a/Mathlib/Order/Filter/Bases.lean +++ b/Mathlib/Order/Filter/Bases.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Yury Kudryashov, Johannes Hölzl, Mario Carneiro, Patrick Massot -/ import Mathlib.Data.Prod.PProd -import Mathlib.Data.Set.Countable import Mathlib.Order.Filter.Finite /-! @@ -77,8 +76,6 @@ machinery, e.g., `simp only [true_and_iff]` or `simp only [forall_const]` can he open Set Filter -section sort - variable {α β γ : Type*} {ι ι' : Sort*} /-- A filter basis `B` on a type `α` is a nonempty collection of sets of `α` @@ -850,215 +847,3 @@ theorem map_sigma_mk_comap {π : α → Type*} {π' : β → Type*} {f : α → apply image_sigmaMk_preimage_sigmaMap hf end Filter - -end sort - -namespace Filter - -variable {α β γ ι : Type*} {ι' : Sort*} - -/-- `IsCountablyGenerated f` means `f = generate s` for some countable `s`. -/ -class IsCountablyGenerated (f : Filter α) : Prop where - /-- There exists a countable set that generates the filter. -/ - out : ∃ s : Set (Set α), s.Countable ∧ f = generate s - -/-- `IsCountableBasis p s` means the image of `s` bounded by `p` is a countable filter basis. -/ -structure IsCountableBasis (p : ι → Prop) (s : ι → Set α) extends IsBasis p s : Prop where - /-- The set of `i` that satisfy the predicate `p` is countable. -/ - countable : (setOf p).Countable - -/-- We say that a filter `l` has a countable basis `s : ι → Set α` bounded by `p : ι → Prop`, -if `t ∈ l` if and only if `t` includes `s i` for some `i` such that `p i`, and the set -defined by `p` is countable. -/ -structure HasCountableBasis (l : Filter α) (p : ι → Prop) (s : ι → Set α) - extends HasBasis l p s : Prop where - /-- The set of `i` that satisfy the predicate `p` is countable. -/ - countable : (setOf p).Countable - -/-- A countable filter basis `B` on a type `α` is a nonempty countable collection of sets of `α` -such that the intersection of two elements of this collection contains some element -of the collection. -/ -structure CountableFilterBasis (α : Type*) extends FilterBasis α where - /-- The set of sets of the filter basis is countable. -/ - countable : sets.Countable - --- For illustration purposes, the countable filter basis defining `(atTop : Filter ℕ)` -instance Nat.inhabitedCountableFilterBasis : Inhabited (CountableFilterBasis ℕ) := - ⟨⟨default, countable_range fun n => Ici n⟩⟩ - -theorem HasCountableBasis.isCountablyGenerated {f : Filter α} {p : ι → Prop} {s : ι → Set α} - (h : f.HasCountableBasis p s) : f.IsCountablyGenerated := - ⟨⟨{ t | ∃ i, p i ∧ s i = t }, h.countable.image s, h.toHasBasis.eq_generate⟩⟩ - -theorem HasBasis.isCountablyGenerated [Countable ι] {f : Filter α} {p : ι → Prop} {s : ι → Set α} - (h : f.HasBasis p s) : f.IsCountablyGenerated := - HasCountableBasis.isCountablyGenerated ⟨h, to_countable _⟩ - -theorem antitone_seq_of_seq (s : ℕ → Set α) : - ∃ t : ℕ → Set α, Antitone t ∧ ⨅ i, 𝓟 (s i) = ⨅ i, 𝓟 (t i) := by - use fun n => ⋂ m ≤ n, s m; constructor - · exact fun i j hij => biInter_mono (Iic_subset_Iic.2 hij) fun n _ => Subset.rfl - apply le_antisymm <;> rw [le_iInf_iff] <;> intro i - · rw [le_principal_iff] - refine (biInter_mem (finite_le_nat _)).2 fun j _ => ?_ - exact mem_iInf_of_mem j (mem_principal_self _) - · refine iInf_le_of_le i (principal_mono.2 <| iInter₂_subset i ?_) - rfl - -theorem countable_biInf_eq_iInf_seq [CompleteLattice α] {B : Set ι} (Bcbl : B.Countable) - (Bne : B.Nonempty) (f : ι → α) : ∃ x : ℕ → ι, ⨅ t ∈ B, f t = ⨅ i, f (x i) := - let ⟨g, hg⟩ := Bcbl.exists_eq_range Bne - ⟨g, hg.symm ▸ iInf_range⟩ - -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 - rcases B.eq_empty_or_nonempty with hB | Bnonempty - · rw [hB, iInf_emptyset] - use fun _ => i₀ - simp [h] - · exact countable_biInf_eq_iInf_seq Bcbl Bnonempty f - -theorem countable_biInf_principal_eq_seq_iInf {B : Set (Set α)} (Bcbl : B.Countable) : - ∃ x : ℕ → Set α, ⨅ t ∈ B, 𝓟 t = ⨅ i, 𝓟 (x i) := - countable_biInf_eq_iInf_seq' Bcbl 𝓟 principal_univ - -section IsCountablyGenerated - -protected theorem HasAntitoneBasis.mem_iff [Preorder ι] {l : Filter α} {s : ι → Set α} - (hs : l.HasAntitoneBasis s) {t : Set α} : t ∈ l ↔ ∃ i, s i ⊆ t := - hs.toHasBasis.mem_iff.trans <| by simp only [exists_prop, true_and] - -protected theorem HasAntitoneBasis.mem [Preorder ι] {l : Filter α} {s : ι → Set α} - (hs : l.HasAntitoneBasis s) (i : ι) : s i ∈ l := - hs.toHasBasis.mem_of_mem trivial - -theorem HasAntitoneBasis.hasBasis_ge [Preorder ι] [IsDirected ι (· ≤ ·)] {l : Filter α} - {s : ι → Set α} (hs : l.HasAntitoneBasis s) (i : ι) : l.HasBasis (fun j => i ≤ j) s := - hs.1.to_hasBasis (fun j _ => (exists_ge_ge i j).imp fun _k hk => ⟨hk.1, hs.2 hk.2⟩) fun j _ => - ⟨j, trivial, Subset.rfl⟩ - -/-- If `f` is countably generated and `f.HasBasis p s`, then `f` admits a decreasing basis -enumerated by natural numbers such that all sets have the form `s i`. More precisely, there is a -sequence `i n` such that `p (i n)` for all `n` and `s (i n)` is a decreasing sequence of sets which -forms a basis of `f`-/ -theorem HasBasis.exists_antitone_subbasis {f : Filter α} [h : f.IsCountablyGenerated] - {p : ι' → Prop} {s : ι' → Set α} (hs : f.HasBasis p s) : - ∃ x : ℕ → ι', (∀ i, p (x i)) ∧ f.HasAntitoneBasis fun i => s (x i) := by - obtain ⟨x', hx'⟩ : ∃ x : ℕ → Set α, f = ⨅ i, 𝓟 (x i) := by - rcases h with ⟨s, hsc, rfl⟩ - rw [generate_eq_biInf] - exact countable_biInf_principal_eq_seq_iInf hsc - have : ∀ i, x' i ∈ f := fun i => hx'.symm ▸ (iInf_le (fun i => 𝓟 (x' i)) i) (mem_principal_self _) - let x : ℕ → { i : ι' // p i } := fun n => - Nat.recOn n (hs.index _ <| this 0) fun n xn => - hs.index _ <| inter_mem (this <| n + 1) (hs.mem_of_mem xn.2) - have x_anti : Antitone fun i => s (x i).1 := - antitone_nat_of_succ_le fun i => (hs.set_index_subset _).trans inter_subset_right - have x_subset : ∀ i, s (x i).1 ⊆ x' i := by - rintro (_ | i) - exacts [hs.set_index_subset _, (hs.set_index_subset _).trans inter_subset_left] - refine ⟨fun i => (x i).1, fun i => (x i).2, ?_⟩ - have : (⨅ i, 𝓟 (s (x i).1)).HasAntitoneBasis fun i => s (x i).1 := .iInf_principal x_anti - convert this - exact - le_antisymm (le_iInf fun i => le_principal_iff.2 <| by cases i <;> apply hs.set_index_mem) - (hx'.symm ▸ - le_iInf fun i => le_principal_iff.2 <| this.1.mem_iff.2 ⟨i, trivial, x_subset i⟩) - -/-- A countably generated filter admits a basis formed by an antitone sequence of sets. -/ -theorem exists_antitone_basis (f : Filter α) [f.IsCountablyGenerated] : - ∃ x : ℕ → Set α, f.HasAntitoneBasis x := - let ⟨x, _, hx⟩ := f.basis_sets.exists_antitone_subbasis - ⟨x, hx⟩ - -theorem exists_antitone_seq (f : Filter α) [f.IsCountablyGenerated] : - ∃ x : ℕ → Set α, Antitone x ∧ ∀ {s}, s ∈ f ↔ ∃ i, x i ⊆ s := - let ⟨x, hx⟩ := f.exists_antitone_basis - ⟨x, hx.antitone, by simp [hx.1.mem_iff]⟩ - -instance Inf.isCountablyGenerated (f g : Filter α) [IsCountablyGenerated f] - [IsCountablyGenerated g] : IsCountablyGenerated (f ⊓ g) := by - rcases f.exists_antitone_basis with ⟨s, hs⟩ - rcases g.exists_antitone_basis with ⟨t, ht⟩ - exact HasCountableBasis.isCountablyGenerated ⟨hs.1.inf ht.1, Set.to_countable _⟩ - -instance map.isCountablyGenerated (l : Filter α) [l.IsCountablyGenerated] (f : α → β) : - (map f l).IsCountablyGenerated := - let ⟨_x, hxl⟩ := l.exists_antitone_basis - (hxl.map _).isCountablyGenerated - -instance comap.isCountablyGenerated (l : Filter β) [l.IsCountablyGenerated] (f : α → β) : - (comap f l).IsCountablyGenerated := - let ⟨_x, hxl⟩ := l.exists_antitone_basis - (hxl.comap _).isCountablyGenerated - -instance Sup.isCountablyGenerated (f g : Filter α) [IsCountablyGenerated f] - [IsCountablyGenerated g] : IsCountablyGenerated (f ⊔ g) := by - rcases f.exists_antitone_basis with ⟨s, hs⟩ - rcases g.exists_antitone_basis with ⟨t, ht⟩ - exact HasCountableBasis.isCountablyGenerated ⟨hs.1.sup ht.1, Set.to_countable _⟩ - -instance prod.isCountablyGenerated (la : Filter α) (lb : Filter β) [IsCountablyGenerated la] - [IsCountablyGenerated lb] : IsCountablyGenerated (la ×ˢ lb) := - Filter.Inf.isCountablyGenerated _ _ - -instance coprod.isCountablyGenerated (la : Filter α) (lb : Filter β) [IsCountablyGenerated la] - [IsCountablyGenerated lb] : IsCountablyGenerated (la.coprod lb) := - Filter.Sup.isCountablyGenerated _ _ - -end IsCountablyGenerated - -theorem isCountablyGenerated_seq [Countable ι'] (x : ι' → Set α) : - IsCountablyGenerated (⨅ i, 𝓟 (x i)) := by - use range x, countable_range x - rw [generate_eq_biInf, iInf_range] - -theorem isCountablyGenerated_of_seq {f : Filter α} (h : ∃ x : ℕ → Set α, f = ⨅ i, 𝓟 (x i)) : - f.IsCountablyGenerated := by - rcases h with ⟨x, rfl⟩ - apply isCountablyGenerated_seq - -theorem isCountablyGenerated_biInf_principal {B : Set (Set α)} (h : B.Countable) : - IsCountablyGenerated (⨅ s ∈ B, 𝓟 s) := - isCountablyGenerated_of_seq (countable_biInf_principal_eq_seq_iInf h) - -theorem isCountablyGenerated_iff_exists_antitone_basis {f : Filter α} : - IsCountablyGenerated f ↔ ∃ x : ℕ → Set α, f.HasAntitoneBasis x := by - constructor - · intro h - exact f.exists_antitone_basis - · rintro ⟨x, h⟩ - rw [h.1.eq_iInf] - exact isCountablyGenerated_seq x - -@[instance] -theorem isCountablyGenerated_principal (s : Set α) : IsCountablyGenerated (𝓟 s) := - isCountablyGenerated_of_seq ⟨fun _ => s, iInf_const.symm⟩ - -@[instance] -theorem isCountablyGenerated_pure (a : α) : IsCountablyGenerated (pure a) := by - rw [← principal_singleton] - exact isCountablyGenerated_principal _ - -@[instance] -theorem isCountablyGenerated_bot : IsCountablyGenerated (⊥ : Filter α) := - @principal_empty α ▸ isCountablyGenerated_principal _ - -@[instance] -theorem isCountablyGenerated_top : IsCountablyGenerated (⊤ : Filter α) := - @principal_univ α ▸ isCountablyGenerated_principal _ - --- Porting note: without explicit `Sort u` and `Type v`, Lean 4 uses `ι : Prop` -universe u v - -instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α) - [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by - choose s hs using fun i => exists_antitone_basis (f i) - rw [← PLift.down_surjective.iInf_comp] - refine HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, ?_⟩ - refine (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono ?_ - rintro ⟨I, f⟩ ⟨hI, -⟩ - lift I to Finset (PLift ι) using hI - exact ⟨⟨I, f⟩, rfl⟩ - -end Filter diff --git a/Mathlib/Order/Filter/Basic.lean b/Mathlib/Order/Filter/Basic.lean index 65c9595abbf40..ddfb081b4e76b 100644 --- a/Mathlib/Order/Filter/Basic.lean +++ b/Mathlib/Order/Filter/Basic.lean @@ -646,6 +646,10 @@ theorem eventually_or_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} (∀ᶠ x in f, p x ∨ q) ↔ (∀ᶠ x in f, p x) ∨ q := by simp only [@or_comm _ q, eventually_or_distrib_left] +theorem eventually_imp_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : + (∀ᶠ x in f, p → q x) ↔ p → ∀ᶠ x in f, q x := by + simp only [imp_iff_not_or, eventually_or_distrib_left] + @[simp] theorem eventually_bot {p : α → Prop} : ∀ᶠ x in ⊥, p x := ⟨⟩ @@ -798,6 +802,16 @@ theorem eventually_imp_distrib_right {f : Filter α} {p : α → Prop} {q : Prop (∀ᶠ x in f, p x → q) ↔ (∃ᶠ x in f, p x) → q := by simp only [imp_iff_not_or, eventually_or_distrib_right, not_frequently] +@[simp] +theorem frequently_and_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : + (∃ᶠ x in f, p ∧ q x) ↔ p ∧ ∃ᶠ x in f, q x := by + simp only [Filter.Frequently, not_and, eventually_imp_distrib_left, Classical.not_imp] + +@[simp] +theorem frequently_and_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} : + (∃ᶠ x in f, p x ∧ q) ↔ (∃ᶠ x in f, p x) ∧ q := by + simp only [@and_comm _ q, frequently_and_distrib_left] + @[simp] theorem frequently_bot {p : α → Prop} : ¬∃ᶠ x in ⊥, p x := by simp diff --git a/Mathlib/Order/Filter/Cofinite.lean b/Mathlib/Order/Filter/Cofinite.lean index 50fbb43ffe460..abcac7aaded93 100644 --- a/Mathlib/Order/Filter/Cofinite.lean +++ b/Mathlib/Order/Filter/Cofinite.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Jeremy Avigad, Yury Kudryashov import Mathlib.Data.Finite.Prod import Mathlib.Data.Fintype.Pi import Mathlib.Order.Filter.AtTopBot +import Mathlib.Order.Filter.CountablyGenerated import Mathlib.Order.Filter.Ker import Mathlib.Order.Filter.Pi diff --git a/Mathlib/Order/Filter/CountablyGenerated.lean b/Mathlib/Order/Filter/CountablyGenerated.lean new file mode 100644 index 0000000000000..dd106b65ece2d --- /dev/null +++ b/Mathlib/Order/Filter/CountablyGenerated.lean @@ -0,0 +1,233 @@ +/- +Copyright (c) 2019 Gabriel Ebner. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Gabriel Ebner, Yury Kudryashov, Patrick Massot +-/ +import Mathlib.Data.Set.Countable +import Mathlib.Order.Filter.Bases + +/-! +# Countably generated filters + +In this file we define a typeclass `Filter.IsCountablyGenerated` +saying that a filter is generated by a countable family of sets. + +We also define predicates `Filter.IsCountableBasis` and `Filter.HasCountableBasis` +saying that a specific family of sets is a countable basis. +-/ + +open Set + +namespace Filter + +variable {α β γ ι : Type*} {ι' : Sort*} + +/-- `IsCountablyGenerated f` means `f = generate s` for some countable `s`. -/ +class IsCountablyGenerated (f : Filter α) : Prop where + /-- There exists a countable set that generates the filter. -/ + out : ∃ s : Set (Set α), s.Countable ∧ f = generate s + +/-- `IsCountableBasis p s` means the image of `s` bounded by `p` is a countable filter basis. -/ +structure IsCountableBasis (p : ι → Prop) (s : ι → Set α) extends IsBasis p s : Prop where + /-- The set of `i` that satisfy the predicate `p` is countable. -/ + countable : (setOf p).Countable + +/-- We say that a filter `l` has a countable basis `s : ι → Set α` bounded by `p : ι → Prop`, +if `t ∈ l` if and only if `t` includes `s i` for some `i` such that `p i`, and the set +defined by `p` is countable. -/ +structure HasCountableBasis (l : Filter α) (p : ι → Prop) (s : ι → Set α) + extends HasBasis l p s : Prop where + /-- The set of `i` that satisfy the predicate `p` is countable. -/ + countable : (setOf p).Countable + +/-- A countable filter basis `B` on a type `α` is a nonempty countable collection of sets of `α` +such that the intersection of two elements of this collection contains some element +of the collection. -/ +structure CountableFilterBasis (α : Type*) extends FilterBasis α where + /-- The set of sets of the filter basis is countable. -/ + countable : sets.Countable + +-- For illustration purposes, the countable filter basis defining `(atTop : Filter ℕ)` +instance Nat.inhabitedCountableFilterBasis : Inhabited (CountableFilterBasis ℕ) := + ⟨⟨default, countable_range fun n => Ici n⟩⟩ + +theorem HasCountableBasis.isCountablyGenerated {f : Filter α} {p : ι → Prop} {s : ι → Set α} + (h : f.HasCountableBasis p s) : f.IsCountablyGenerated := + ⟨⟨{ t | ∃ i, p i ∧ s i = t }, h.countable.image s, h.toHasBasis.eq_generate⟩⟩ + +theorem HasBasis.isCountablyGenerated [Countable ι] {f : Filter α} {p : ι → Prop} {s : ι → Set α} + (h : f.HasBasis p s) : f.IsCountablyGenerated := + HasCountableBasis.isCountablyGenerated ⟨h, to_countable _⟩ + +theorem antitone_seq_of_seq (s : ℕ → Set α) : + ∃ t : ℕ → Set α, Antitone t ∧ ⨅ i, 𝓟 (s i) = ⨅ i, 𝓟 (t i) := by + use fun n => ⋂ m ≤ n, s m; constructor + · exact fun i j hij => biInter_mono (Iic_subset_Iic.2 hij) fun n _ => Subset.rfl + apply le_antisymm <;> rw [le_iInf_iff] <;> intro i + · rw [le_principal_iff] + refine (biInter_mem (finite_le_nat _)).2 fun j _ => ?_ + exact mem_iInf_of_mem j (mem_principal_self _) + · refine iInf_le_of_le i (principal_mono.2 <| iInter₂_subset i ?_) + rfl + +theorem countable_biInf_eq_iInf_seq [CompleteLattice α] {B : Set ι} (Bcbl : B.Countable) + (Bne : B.Nonempty) (f : ι → α) : ∃ x : ℕ → ι, ⨅ t ∈ B, f t = ⨅ i, f (x i) := + let ⟨g, hg⟩ := Bcbl.exists_eq_range Bne + ⟨g, hg.symm ▸ iInf_range⟩ + +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 + rcases B.eq_empty_or_nonempty with hB | Bnonempty + · rw [hB, iInf_emptyset] + use fun _ => i₀ + simp [h] + · exact countable_biInf_eq_iInf_seq Bcbl Bnonempty f + +theorem countable_biInf_principal_eq_seq_iInf {B : Set (Set α)} (Bcbl : B.Countable) : + ∃ x : ℕ → Set α, ⨅ t ∈ B, 𝓟 t = ⨅ i, 𝓟 (x i) := + countable_biInf_eq_iInf_seq' Bcbl 𝓟 principal_univ + +section IsCountablyGenerated + +protected theorem HasAntitoneBasis.mem_iff [Preorder ι] {l : Filter α} {s : ι → Set α} + (hs : l.HasAntitoneBasis s) {t : Set α} : t ∈ l ↔ ∃ i, s i ⊆ t := + hs.toHasBasis.mem_iff.trans <| by simp only [exists_prop, true_and] + +protected theorem HasAntitoneBasis.mem [Preorder ι] {l : Filter α} {s : ι → Set α} + (hs : l.HasAntitoneBasis s) (i : ι) : s i ∈ l := + hs.toHasBasis.mem_of_mem trivial + +theorem HasAntitoneBasis.hasBasis_ge [Preorder ι] [IsDirected ι (· ≤ ·)] {l : Filter α} + {s : ι → Set α} (hs : l.HasAntitoneBasis s) (i : ι) : l.HasBasis (fun j => i ≤ j) s := + hs.1.to_hasBasis (fun j _ => (exists_ge_ge i j).imp fun _k hk => ⟨hk.1, hs.2 hk.2⟩) fun j _ => + ⟨j, trivial, Subset.rfl⟩ + +/-- If `f` is countably generated and `f.HasBasis p s`, then `f` admits a decreasing basis +enumerated by natural numbers such that all sets have the form `s i`. More precisely, there is a +sequence `i n` such that `p (i n)` for all `n` and `s (i n)` is a decreasing sequence of sets which +forms a basis of `f`-/ +theorem HasBasis.exists_antitone_subbasis {f : Filter α} [h : f.IsCountablyGenerated] + {p : ι' → Prop} {s : ι' → Set α} (hs : f.HasBasis p s) : + ∃ x : ℕ → ι', (∀ i, p (x i)) ∧ f.HasAntitoneBasis fun i => s (x i) := by + obtain ⟨x', hx'⟩ : ∃ x : ℕ → Set α, f = ⨅ i, 𝓟 (x i) := by + rcases h with ⟨s, hsc, rfl⟩ + rw [generate_eq_biInf] + exact countable_biInf_principal_eq_seq_iInf hsc + have : ∀ i, x' i ∈ f := fun i => hx'.symm ▸ (iInf_le (fun i => 𝓟 (x' i)) i) (mem_principal_self _) + let x : ℕ → { i : ι' // p i } := fun n => + Nat.recOn n (hs.index _ <| this 0) fun n xn => + hs.index _ <| inter_mem (this <| n + 1) (hs.mem_of_mem xn.2) + have x_anti : Antitone fun i => s (x i).1 := + antitone_nat_of_succ_le fun i => (hs.set_index_subset _).trans inter_subset_right + have x_subset : ∀ i, s (x i).1 ⊆ x' i := by + rintro (_ | i) + exacts [hs.set_index_subset _, (hs.set_index_subset _).trans inter_subset_left] + refine ⟨fun i => (x i).1, fun i => (x i).2, ?_⟩ + have : (⨅ i, 𝓟 (s (x i).1)).HasAntitoneBasis fun i => s (x i).1 := .iInf_principal x_anti + convert this + exact + le_antisymm (le_iInf fun i => le_principal_iff.2 <| by cases i <;> apply hs.set_index_mem) + (hx'.symm ▸ + le_iInf fun i => le_principal_iff.2 <| this.1.mem_iff.2 ⟨i, trivial, x_subset i⟩) + +/-- A countably generated filter admits a basis formed by an antitone sequence of sets. -/ +theorem exists_antitone_basis (f : Filter α) [f.IsCountablyGenerated] : + ∃ x : ℕ → Set α, f.HasAntitoneBasis x := + let ⟨x, _, hx⟩ := f.basis_sets.exists_antitone_subbasis + ⟨x, hx⟩ + +theorem exists_antitone_seq (f : Filter α) [f.IsCountablyGenerated] : + ∃ x : ℕ → Set α, Antitone x ∧ ∀ {s}, s ∈ f ↔ ∃ i, x i ⊆ s := + let ⟨x, hx⟩ := f.exists_antitone_basis + ⟨x, hx.antitone, by simp [hx.1.mem_iff]⟩ + +instance Inf.isCountablyGenerated (f g : Filter α) [IsCountablyGenerated f] + [IsCountablyGenerated g] : IsCountablyGenerated (f ⊓ g) := by + rcases f.exists_antitone_basis with ⟨s, hs⟩ + rcases g.exists_antitone_basis with ⟨t, ht⟩ + exact HasCountableBasis.isCountablyGenerated ⟨hs.1.inf ht.1, Set.to_countable _⟩ + +instance map.isCountablyGenerated (l : Filter α) [l.IsCountablyGenerated] (f : α → β) : + (map f l).IsCountablyGenerated := + let ⟨_x, hxl⟩ := l.exists_antitone_basis + (hxl.map _).isCountablyGenerated + +instance comap.isCountablyGenerated (l : Filter β) [l.IsCountablyGenerated] (f : α → β) : + (comap f l).IsCountablyGenerated := + let ⟨_x, hxl⟩ := l.exists_antitone_basis + (hxl.comap _).isCountablyGenerated + +instance Sup.isCountablyGenerated (f g : Filter α) [IsCountablyGenerated f] + [IsCountablyGenerated g] : IsCountablyGenerated (f ⊔ g) := by + rcases f.exists_antitone_basis with ⟨s, hs⟩ + rcases g.exists_antitone_basis with ⟨t, ht⟩ + exact HasCountableBasis.isCountablyGenerated ⟨hs.1.sup ht.1, Set.to_countable _⟩ + +instance prod.isCountablyGenerated (la : Filter α) (lb : Filter β) [IsCountablyGenerated la] + [IsCountablyGenerated lb] : IsCountablyGenerated (la ×ˢ lb) := + Filter.Inf.isCountablyGenerated _ _ + +instance coprod.isCountablyGenerated (la : Filter α) (lb : Filter β) [IsCountablyGenerated la] + [IsCountablyGenerated lb] : IsCountablyGenerated (la.coprod lb) := + Filter.Sup.isCountablyGenerated _ _ + +end IsCountablyGenerated + +theorem isCountablyGenerated_seq [Countable ι'] (x : ι' → Set α) : + IsCountablyGenerated (⨅ i, 𝓟 (x i)) := by + use range x, countable_range x + rw [generate_eq_biInf, iInf_range] + +theorem isCountablyGenerated_of_seq {f : Filter α} (h : ∃ x : ℕ → Set α, f = ⨅ i, 𝓟 (x i)) : + f.IsCountablyGenerated := by + rcases h with ⟨x, rfl⟩ + apply isCountablyGenerated_seq + +theorem isCountablyGenerated_biInf_principal {B : Set (Set α)} (h : B.Countable) : + IsCountablyGenerated (⨅ s ∈ B, 𝓟 s) := + isCountablyGenerated_of_seq (countable_biInf_principal_eq_seq_iInf h) + +theorem isCountablyGenerated_iff_exists_antitone_basis {f : Filter α} : + IsCountablyGenerated f ↔ ∃ x : ℕ → Set α, f.HasAntitoneBasis x := by + constructor + · intro h + exact f.exists_antitone_basis + · rintro ⟨x, h⟩ + rw [h.1.eq_iInf] + exact isCountablyGenerated_seq x + +@[instance] +theorem isCountablyGenerated_principal (s : Set α) : IsCountablyGenerated (𝓟 s) := + isCountablyGenerated_of_seq ⟨fun _ => s, iInf_const.symm⟩ + +@[instance] +theorem isCountablyGenerated_pure (a : α) : IsCountablyGenerated (pure a) := by + rw [← principal_singleton] + exact isCountablyGenerated_principal _ + +@[instance] +theorem isCountablyGenerated_bot : IsCountablyGenerated (⊥ : Filter α) := + @principal_empty α ▸ isCountablyGenerated_principal _ + +@[instance] +theorem isCountablyGenerated_top : IsCountablyGenerated (⊤ : Filter α) := + @principal_univ α ▸ isCountablyGenerated_principal _ + +-- Porting note: without explicit `Sort u` and `Type v`, Lean 4 uses `ι : Prop` +universe u v + +instance iInf.isCountablyGenerated {ι : Sort u} {α : Type v} [Countable ι] (f : ι → Filter α) + [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (⨅ i, f i) := by + choose s hs using fun i => exists_antitone_basis (f i) + rw [← PLift.down_surjective.iInf_comp] + refine HasCountableBasis.isCountablyGenerated ⟨hasBasis_iInf fun n => (hs _).1, ?_⟩ + refine (countable_range <| Sigma.map ((↑) : Finset (PLift ι) → Set (PLift ι)) fun _ => id).mono ?_ + rintro ⟨I, f⟩ ⟨hI, -⟩ + lift I to Finset (PLift ι) using hI + exact ⟨⟨I, f⟩, rfl⟩ + +instance pi.isCountablyGenerated {ι : Type*} {α : ι → Type*} [Countable ι] + (f : ∀ i, Filter (α i)) [∀ i, IsCountablyGenerated (f i)] : IsCountablyGenerated (pi f) := + iInf.isCountablyGenerated _ + +end Filter diff --git a/Mathlib/Order/Filter/Curry.lean b/Mathlib/Order/Filter/Curry.lean index 7f91d3cc76ef9..5d0fb17e49630 100644 --- a/Mathlib/Order/Filter/Curry.lean +++ b/Mathlib/Order/Filter/Curry.lean @@ -47,46 +47,34 @@ uniform convergence, curried filters, product filters namespace Filter -variable {α β γ : Type*} +variable {α β γ : Type*} {l : Filter α} {m : Filter β} {s : Set α} {t : Set β} -theorem eventually_curry_iff {f : Filter α} {g : Filter β} {p : α × β → Prop} : - (∀ᶠ x : α × β in f.curry g, p x) ↔ ∀ᶠ x : α in f, ∀ᶠ y : β in g, p (x, y) := +theorem eventually_curry_iff {p : α × β → Prop} : + (∀ᶠ x : α × β in l.curry m, p x) ↔ ∀ᶠ x : α in l, ∀ᶠ y : β in m, p (x, y) := Iff.rfl -theorem frequently_curry_iff {α β : Type*} {l : Filter α} {m : Filter β} +theorem frequently_curry_iff (p : (α × β) → Prop) : (∃ᶠ x in l.curry m, p x) ↔ ∃ᶠ x in l, ∃ᶠ y in m, p (x, y) := by simp_rw [Filter.Frequently, not_iff_not, not_not, eventually_curry_iff] -theorem mem_curry_iff {f : Filter α} {g : Filter β} {s : Set (α × β)} : - s ∈ f.curry g ↔ ∀ᶠ x : α in f, ∀ᶠ y : β in g, (x, y) ∈ s := Iff.rfl +theorem mem_curry_iff {s : Set (α × β)} : + s ∈ l.curry m ↔ ∀ᶠ x : α in l, ∀ᶠ y : β in m, (x, y) ∈ s := Iff.rfl -theorem curry_le_prod {f : Filter α} {g : Filter β} : f.curry g ≤ f.prod g := - fun _ => Eventually.curry +theorem curry_le_prod : l.curry m ≤ l ×ˢ m := fun _ => Eventually.curry theorem Tendsto.curry {f : α → β → γ} {la : Filter α} {lb : Filter β} {lc : Filter γ} (h : ∀ᶠ a in la, Tendsto (fun b : β => f a b) lb lc) : Tendsto (↿f) (la.curry lb) lc := fun _s hs => h.mono fun _a ha => ha hs -theorem frequently_curry_prod_iff {α β : Type*} {l : Filter α} {m : Filter β} - (s : Set α) (t : Set β) : (∃ᶠ x in l.curry m, x ∈ s ×ˢ t) ↔ sᶜ ∉ l ∧ tᶜ ∉ m := by - refine ⟨fun h => ?_, fun ⟨hs, ht⟩ => ?_⟩ - · exact frequently_prod_and.mp (Frequently.filter_mono h curry_le_prod) - rw [frequently_curry_iff] - exact Frequently.mono hs <| fun x hx => Frequently.mono ht (by simp [hx]) +theorem frequently_curry_prod_iff : + (∃ᶠ x in l.curry m, x ∈ s ×ˢ t) ↔ (∃ᶠ x in l, x ∈ s) ∧ ∃ᶠ y in m, y ∈ t := by + simp [frequently_curry_iff] -theorem prod_mem_curry {α β : Type*} {l : Filter α} {m : Filter β} {s : Set α} {t : Set β} - (hs : s ∈ l) (ht : t ∈ m) : s ×ˢ t ∈ l.curry m := - curry_le_prod <| prod_mem_prod hs ht - -theorem eventually_curry_prod_iff {α β : Type*} {l : Filter α} {m : Filter β} - [NeBot l] [NeBot m] (s : Set α) (t : Set β) : +theorem eventually_curry_prod_iff [NeBot l] [NeBot m] : (∀ᶠ x in l.curry m, x ∈ s ×ˢ t) ↔ s ∈ l ∧ t ∈ m := by - refine ⟨fun h => ⟨?_, ?_⟩, fun ⟨hs, ht⟩ => prod_mem_curry hs ht⟩ <;> - rw [eventually_curry_iff] at h - · apply mem_of_superset h - simp - rcases h.exists with ⟨_, hx⟩ - apply mem_of_superset hx - exact fun _ hy => hy.2 + simp [eventually_curry_iff] + +theorem prod_mem_curry (hs : s ∈ l) (ht : t ∈ m) : s ×ˢ t ∈ l.curry m := + curry_le_prod <| prod_mem_prod hs ht end Filter diff --git a/Mathlib/Order/Filter/Defs.lean b/Mathlib/Order/Filter/Defs.lean index d0a00823afb8a..769d8eb31e206 100644 --- a/Mathlib/Order/Filter/Defs.lean +++ b/Mathlib/Order/Filter/Defs.lean @@ -301,21 +301,28 @@ def comap (m : α → β) (f : Filter β) : Filter α where inter_sets := fun ⟨a', ha₁, ha₂⟩ ⟨b', hb₁, hb₂⟩ => ⟨a' ∩ b', inter_mem ha₁ hb₁, inter_subset_inter ha₂ hb₂⟩ -/-- Product of filters. This is the filter generated by cartesian products -of elements of the component filters. -/ -protected def prod (f : Filter α) (g : Filter β) : Filter (α × β) := - f.comap Prod.fst ⊓ g.comap Prod.snd - /-- Coproduct of filters. -/ protected def coprod (f : Filter α) (g : Filter β) : Filter (α × β) := f.comap Prod.fst ⊔ g.comap Prod.snd +/-- Product of filters. This is the filter generated by cartesian products +of elements of the component filters. -/ instance instSProd : SProd (Filter α) (Filter β) (Filter (α × β)) where - sprod := Filter.prod + sprod f g := f.comap Prod.fst ⊓ g.comap Prod.snd + +/-- Product of filters. This is the filter generated by cartesian products +of elements of the component filters. +Deprecated. Use `f ×ˢ g` instead. -/ +@[deprecated " Use `f ×ˢ g` instead." (since := "2024-11-29")] +protected def prod (f : Filter α) (g : Filter β) : Filter (α × β) := f ×ˢ g theorem prod_eq_inf (f : Filter α) (g : Filter β) : f ×ˢ g = f.comap Prod.fst ⊓ g.comap Prod.snd := rfl +/-- The product of an indexed family of filters. -/ +def pi {ι : Type*} {α : ι → Type*} (f : ∀ i, Filter (α i)) : Filter (∀ i, α i) := + ⨅ i, comap (Function.eval i) (f i) + /-- The monadic bind operation on filter is defined the usual way in terms of `map` and `join`. Unfortunately, this `bind` does not result in the expected applicative. See `Filter.seq` for the diff --git a/Mathlib/Order/Filter/Finite.lean b/Mathlib/Order/Filter/Finite.lean index 2c96231b9a89f..a10cfa503fa90 100644 --- a/Mathlib/Order/Filter/Finite.lean +++ b/Mathlib/Order/Filter/Finite.lean @@ -263,23 +263,6 @@ alias _root_.Finset.eventually_all := eventually_all_finset -- attribute [protected] Finset.eventually_all -theorem eventually_imp_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : - (∀ᶠ x in f, p → q x) ↔ p → ∀ᶠ x in f, q x := - eventually_all - - -/-! ### Frequently -/ - -@[simp] -theorem frequently_and_distrib_left {f : Filter α} {p : Prop} {q : α → Prop} : - (∃ᶠ x in f, p ∧ q x) ↔ p ∧ ∃ᶠ x in f, q x := by - simp only [Filter.Frequently, not_and, eventually_imp_distrib_left, Classical.not_imp] - -@[simp] -theorem frequently_and_distrib_right {f : Filter α} {p : α → Prop} {q : Prop} : - (∃ᶠ x in f, p x ∧ q) ↔ (∃ᶠ x in f, p x) ∧ q := by - simp only [@and_comm _ q, frequently_and_distrib_left] - /-! ### Relation “eventually equal” -/ diff --git a/Mathlib/Order/Filter/Germ/Basic.lean b/Mathlib/Order/Filter/Germ/Basic.lean index c9ad7754c4946..fe099e6b204fa 100644 --- a/Mathlib/Order/Filter/Germ/Basic.lean +++ b/Mathlib/Order/Filter/Germ/Basic.lean @@ -5,7 +5,8 @@ Authors: Yury Kudryashov, Abhimanyu Pallavi Sudhir -/ import Mathlib.Algebra.Module.Pi import Mathlib.Algebra.Order.Monoid.Unbundled.ExistsOfLE -import Mathlib.Data.Int.Cast.Lemmas +import Mathlib.Data.Int.Cast.Pi +import Mathlib.Data.Nat.Cast.Basic import Mathlib.Order.Filter.Tendsto /-! @@ -197,7 +198,7 @@ theorem map_map (op₁ : γ → δ) (op₂ : β → γ) (f : Germ l β) : /-- Lift a binary function `β → γ → δ` to a function `Germ l β → Germ l γ → Germ l δ`. -/ def map₂ (op : β → γ → δ) : Germ l β → Germ l γ → Germ l δ := - Quotient.map₂' (fun f g x => op (f x) (g x)) fun f f' Hf g g' Hg => + Quotient.map₂ (fun f g x => op (f x) (g x)) fun f f' Hf g g' Hg => Hg.mp <| Hf.mono fun x Hf Hg => by simp only [Hf, Hg] @[simp] diff --git a/Mathlib/Order/Filter/Pi.lean b/Mathlib/Order/Filter/Pi.lean index 10716f6ff6edc..e583584b9123e 100644 --- a/Mathlib/Order/Filter/Pi.lean +++ b/Mathlib/Order/Filter/Pi.lean @@ -30,14 +30,6 @@ variable {ι : Type*} {α : ι → Type*} {f f₁ f₂ : (i : ι) → Filter (α section Pi -/-- The product of an indexed family of filters. -/ -def pi (f : ∀ i, Filter (α i)) : Filter (∀ i, α i) := - ⨅ i, comap (eval i) (f i) - -instance pi.isCountablyGenerated [Countable ι] [∀ i, IsCountablyGenerated (f i)] : - IsCountablyGenerated (pi f) := - iInf.isCountablyGenerated _ - theorem tendsto_eval_pi (f : ∀ i, Filter (α i)) (i : ι) : Tendsto (eval i) (pi f) (f i) := tendsto_iInf' i tendsto_comap diff --git a/Mathlib/Order/Filter/Prod.lean b/Mathlib/Order/Filter/Prod.lean index 5a1d1ab10faa6..652a0c81b4dc6 100644 --- a/Mathlib/Order/Filter/Prod.lean +++ b/Mathlib/Order/Filter/Prod.lean @@ -51,7 +51,6 @@ theorem prod_mem_prod (hs : s ∈ f) (ht : t ∈ g) : s ×ˢ t ∈ f ×ˢ g := theorem mem_prod_iff {s : Set (α × β)} {f : Filter α} {g : Filter β} : s ∈ f ×ˢ g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ ×ˢ t₂ ⊆ s := by - simp only [SProd.sprod, Filter.prod] constructor · rintro ⟨t₁, ⟨s₁, hs₁, hts₁⟩, t₂, ⟨s₂, hs₂, hts₂⟩, rfl⟩ exact ⟨s₁, hs₁, s₂, hs₂, fun p ⟨h, h'⟩ => ⟨hts₁ h, hts₂ h'⟩⟩ @@ -100,20 +99,16 @@ theorem comap_prodMap_prod (f : α → β) (g : γ → δ) (lb : Filter β) (ld simp [prod_eq_inf, comap_comap, Function.comp_def] theorem prod_top : f ×ˢ (⊤ : Filter β) = f.comap Prod.fst := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_top, inf_top_eq] + rw [prod_eq_inf, comap_top, inf_top_eq] theorem top_prod : (⊤ : Filter α) ×ˢ g = g.comap Prod.snd := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_top, top_inf_eq] + rw [prod_eq_inf, comap_top, top_inf_eq] theorem sup_prod (f₁ f₂ : Filter α) (g : Filter β) : (f₁ ⊔ f₂) ×ˢ g = (f₁ ×ˢ g) ⊔ (f₂ ×ˢ g) := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_sup, inf_sup_right, ← Filter.prod, ← Filter.prod] + simp only [prod_eq_inf, comap_sup, inf_sup_right] theorem prod_sup (f : Filter α) (g₁ g₂ : Filter β) : f ×ˢ (g₁ ⊔ g₂) = (f ×ˢ g₁) ⊔ (f ×ˢ g₂) := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_sup, inf_sup_left, ← Filter.prod, ← Filter.prod] + simp only [prod_eq_inf, comap_sup, inf_sup_left] theorem eventually_prod_iff {p : α × β → Prop} : (∀ᶠ x in f ×ˢ g, p x) ↔ @@ -203,15 +198,11 @@ theorem tendsto_diag : Tendsto (fun i => (i, i)) f (f ×ˢ f) := theorem prod_iInf_left [Nonempty ι] {f : ι → Filter α} {g : Filter β} : (⨅ i, f i) ×ˢ g = ⨅ i, f i ×ˢ g := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_iInf, iInf_inf] - simp only [Filter.prod, eq_self_iff_true] + simp only [prod_eq_inf, comap_iInf, iInf_inf] theorem prod_iInf_right [Nonempty ι] {f : Filter α} {g : ι → Filter β} : (f ×ˢ ⨅ i, g i) = ⨅ i, f ×ˢ g i := by - dsimp only [SProd.sprod] - rw [Filter.prod, comap_iInf, inf_iInf] - simp only [Filter.prod, eq_self_iff_true] + simp only [prod_eq_inf, comap_iInf, inf_iInf] @[mono, gcongr] theorem prod_mono {f₁ f₂ : Filter α} {g₁ g₂ : Filter β} (hf : f₁ ≤ f₂) (hg : g₁ ≤ g₂) : @@ -229,11 +220,10 @@ theorem prod_mono_right (f : Filter α) {g₁ g₂ : Filter β} (hf : g₁ ≤ g theorem prod_comap_comap_eq.{u, v, w, x} {α₁ : Type u} {α₂ : Type v} {β₁ : Type w} {β₂ : Type x} {f₁ : Filter α₁} {f₂ : Filter α₂} {m₁ : β₁ → α₁} {m₂ : β₂ → α₂} : comap m₁ f₁ ×ˢ comap m₂ f₂ = comap (fun p : β₁ × β₂ => (m₁ p.1, m₂ p.2)) (f₁ ×ˢ f₂) := by - simp only [SProd.sprod, Filter.prod, comap_comap, comap_inf, Function.comp_def] + simp only [prod_eq_inf, comap_comap, comap_inf, Function.comp_def] theorem prod_comm' : f ×ˢ g = comap Prod.swap (g ×ˢ f) := by - simp only [SProd.sprod, Filter.prod, comap_comap, Function.comp_def, inf_comm, Prod.swap, - comap_inf] + simp only [prod_eq_inf, comap_comap, Function.comp_def, inf_comm, Prod.swap, comap_inf] theorem prod_comm : f ×ˢ g = map (fun p : β × α => (p.2, p.1)) (g ×ˢ f) := by rw [prod_comm', ← map_swap_eq_comap_swap] @@ -280,12 +270,12 @@ theorem eventually_swap_iff {p : α × β → Prop} : theorem prod_assoc (f : Filter α) (g : Filter β) (h : Filter γ) : map (Equiv.prodAssoc α β γ) ((f ×ˢ g) ×ˢ h) = f ×ˢ (g ×ˢ h) := by - simp_rw [← comap_equiv_symm, SProd.sprod, Filter.prod, comap_inf, comap_comap, inf_assoc, + simp_rw [← comap_equiv_symm, prod_eq_inf, comap_inf, comap_comap, inf_assoc, Function.comp_def, Equiv.prodAssoc_symm_apply] theorem prod_assoc_symm (f : Filter α) (g : Filter β) (h : Filter γ) : map (Equiv.prodAssoc α β γ).symm (f ×ˢ (g ×ˢ h)) = (f ×ˢ g) ×ˢ h := by - simp_rw [map_equiv_symm, SProd.sprod, Filter.prod, comap_inf, comap_comap, inf_assoc, + simp_rw [map_equiv_symm, prod_eq_inf, comap_inf, comap_comap, inf_assoc, Function.comp_def, Equiv.prodAssoc_apply] theorem tendsto_prodAssoc {h : Filter γ} : @@ -300,7 +290,7 @@ theorem tendsto_prodAssoc_symm {h : Filter γ} : theorem map_swap4_prod {h : Filter γ} {k : Filter δ} : map (fun p : (α × β) × γ × δ => ((p.1.1, p.2.1), (p.1.2, p.2.2))) ((f ×ˢ g) ×ˢ (h ×ˢ k)) = (f ×ˢ h) ×ˢ (g ×ˢ k) := by - simp_rw [map_swap4_eq_comap, SProd.sprod, Filter.prod, comap_inf, comap_comap]; ac_rfl + simp_rw [map_swap4_eq_comap, prod_eq_inf, comap_inf, comap_comap]; ac_rfl theorem tendsto_swap4_prod {h : Filter γ} {k : Filter δ} : Tendsto (fun p : (α × β) × γ × δ => ((p.1.1, p.2.1), (p.1.2, p.2.2))) ((f ×ˢ g) ×ˢ (h ×ˢ k)) @@ -351,7 +341,7 @@ theorem prod_eq : f ×ˢ g = (f.map Prod.mk).seq g := f.map_prod id g theorem prod_inf_prod {f₁ f₂ : Filter α} {g₁ g₂ : Filter β} : (f₁ ×ˢ g₁) ⊓ (f₂ ×ˢ g₂) = (f₁ ⊓ f₂) ×ˢ (g₁ ⊓ g₂) := by - simp only [SProd.sprod, Filter.prod, comap_inf, inf_comm, inf_assoc, inf_left_comm] + simp only [prod_eq_inf, comap_inf, inf_comm, inf_assoc, inf_left_comm] theorem inf_prod {f₁ f₂ : Filter α} : (f₁ ⊓ f₂) ×ˢ g = (f₁ ×ˢ g) ⊓ (f₂ ×ˢ g) := by rw [prod_inf_prod, inf_idem] @@ -361,8 +351,7 @@ theorem prod_inf {g₁ g₂ : Filter β} : f ×ˢ (g₁ ⊓ g₂) = (f ×ˢ g₁ @[simp] theorem prod_principal_principal {s : Set α} {t : Set β} : 𝓟 s ×ˢ 𝓟 t = 𝓟 (s ×ˢ t) := by - simp only [SProd.sprod, Filter.prod, comap_principal, principal_eq_iff_eq, comap_principal, - inf_principal]; rfl + simp only [prod_eq_inf, comap_principal, principal_eq_iff_eq, comap_principal, inf_principal]; rfl @[simp] theorem pure_prod {a : α} {f : Filter β} : pure a ×ˢ f = map (Prod.mk a) f := by @@ -413,9 +402,7 @@ theorem tendsto_prod_iff {f : α × β → γ} {x : Filter α} {y : Filter β} { theorem tendsto_prod_iff' {g' : Filter γ} {s : α → β × γ} : Tendsto s f (g ×ˢ g') ↔ Tendsto (fun n => (s n).1) f g ∧ Tendsto (fun n => (s n).2) f g' := by - dsimp only [SProd.sprod] - unfold Filter.prod - simp only [tendsto_inf, tendsto_comap_iff, Function.comp_def] + simp only [prod_eq_inf, tendsto_inf, tendsto_comap_iff, Function.comp_def] theorem le_prod {f : Filter (α × β)} {g : Filter α} {g' : Filter β} : (f ≤ g ×ˢ g') ↔ Tendsto Prod.fst f g ∧ Tendsto Prod.snd f g' := @@ -468,6 +455,15 @@ theorem coprod_neBot_left [NeBot f] [Nonempty β] : (f.coprod g).NeBot := theorem coprod_neBot_right [NeBot g] [Nonempty α] : (f.coprod g).NeBot := coprod_neBot_iff.2 (Or.inr ⟨‹_›, ‹_›⟩) +theorem coprod_inf_prod_le (f₁ f₂ : Filter α) (g₁ g₂ : Filter β) : + f₁.coprod g₁ ⊓ f₂ ×ˢ g₂ ≤ f₁ ×ˢ g₂ ⊔ f₂ ×ˢ g₁ := calc + f₁.coprod g₁ ⊓ f₂ ×ˢ g₂ + _ = (f₁ ×ˢ ⊤ ⊔ ⊤ ×ˢ g₁) ⊓ f₂ ×ˢ g₂ := by rw [coprod_eq_prod_top_sup_top_prod] + _ = f₁ ×ˢ ⊤ ⊓ f₂ ×ˢ g₂ ⊔ ⊤ ×ˢ g₁ ⊓ f₂ ×ˢ g₂ := inf_sup_right _ _ _ + _ = (f₁ ⊓ f₂) ×ˢ g₂ ⊔ f₂ ×ˢ (g₁ ⊓ g₂) := by simp [prod_inf_prod] + _ ≤ f₁ ×ˢ g₂ ⊔ f₂ ×ˢ g₁ := + sup_le_sup (prod_mono inf_le_left le_rfl) (prod_mono le_rfl inf_le_left) + theorem principal_coprod_principal (s : Set α) (t : Set β) : (𝓟 s).coprod (𝓟 t) = 𝓟 (sᶜ ×ˢ tᶜ)ᶜ := by rw [Filter.coprod, comap_principal, comap_principal, sup_principal, Set.prod_eq, compl_inter, diff --git a/Mathlib/Order/Ideal.lean b/Mathlib/Order/Ideal.lean index 30f3f80385924..7603c89a04604 100644 --- a/Mathlib/Order/Ideal.lean +++ b/Mathlib/Order/Ideal.lean @@ -6,6 +6,7 @@ Authors: David Wärn import Mathlib.Logic.Encodable.Basic import Mathlib.Order.Atoms import Mathlib.Order.Chain +import Mathlib.Order.Cofinal import Mathlib.Order.UpperLower.Basic import Mathlib.Data.Set.Subsingleton @@ -463,15 +464,17 @@ structure Cofinal (P) [Preorder P] where /-- The carrier of a `Cofinal` is the underlying set. -/ carrier : Set P /-- The `Cofinal` contains arbitrarily large elements. -/ - mem_gt : ∀ x : P, ∃ y ∈ carrier, x ≤ y + isCofinal : IsCofinal carrier + +@[deprecated Cofinal.isCofinal (since := "2024-12-02")] +alias Cofinal.mem_gt := Cofinal.isCofinal namespace Cofinal variable [Preorder P] instance : Inhabited (Cofinal P) := - ⟨{ carrier := univ - mem_gt := fun x ↦ ⟨x, trivial, le_rfl⟩ }⟩ + ⟨_, .univ⟩ instance : Membership P (Cofinal P) := ⟨fun D x ↦ x ∈ D.carrier⟩ @@ -480,13 +483,13 @@ variable (D : Cofinal P) (x : P) /-- A (noncomputable) element of a cofinal set lying above a given element. -/ noncomputable def above : P := - Classical.choose <| D.mem_gt x + Classical.choose <| D.isCofinal x theorem above_mem : D.above x ∈ D := - (Classical.choose_spec <| D.mem_gt x).1 + (Classical.choose_spec <| D.isCofinal x).1 theorem le_above : x ≤ D.above x := - (Classical.choose_spec <| D.mem_gt x).2 + (Classical.choose_spec <| D.isCofinal x).2 end Cofinal diff --git a/Mathlib/Order/InitialSeg.lean b/Mathlib/Order/InitialSeg.lean index b09f50366e0c0..9d83ed92d1c08 100644 --- a/Mathlib/Order/InitialSeg.lean +++ b/Mathlib/Order/InitialSeg.lean @@ -7,6 +7,7 @@ import Mathlib.Data.Sum.Order import Mathlib.Logic.Equiv.Set import Mathlib.Order.RelIso.Set import Mathlib.Order.WellFounded + /-! # Initial and principal segments @@ -656,12 +657,15 @@ theorem monotone [PartialOrder α] (f : α ≤i β) : Monotone f := theorem strictMono [PartialOrder α] (f : α ≤i β) : StrictMono f := f.toOrderEmbedding.strictMono -theorem map_isMin [PartialOrder α] (f : α ≤i β) (h : IsMin a) : IsMin (f a) := by - intro b hb +@[simp] +theorem isMin_apply_iff [PartialOrder α] (f : α ≤i β) : IsMin (f a) ↔ IsMin a := by + refine ⟨StrictMono.isMin_of_apply f.strictMono, fun h b hb ↦ ?_⟩ obtain ⟨x, rfl⟩ := f.mem_range_of_le hb rw [f.le_iff_le] at hb ⊢ exact h hb +alias ⟨_, map_isMin⟩ := isMin_apply_iff + @[simp] theorem map_bot [PartialOrder α] [OrderBot α] [OrderBot β] (f : α ≤i β) : f ⊥ = ⊥ := (map_isMin f isMin_bot).eq_bot @@ -712,8 +716,11 @@ theorem monotone [PartialOrder α] (f : α (hx _ ha).1.trans (hx _ hb).2 @[simp, norm_cast] -theorem coe_iInf [@DecidableRel α (· ≤ ·)] (f : ι → Interval α) : +theorem coe_iInf [DecidableRel (α := α) (· ≤ ·)] (f : ι → Interval α) : ↑(⨅ i, f i) = ⋂ i, (f i : Set α) := by simp [iInf] -- @[simp] -- Porting note: not in simpNF @[norm_cast] -theorem coe_iInf₂ [@DecidableRel α (· ≤ ·)] (f : ∀ i, κ i → Interval α) : +theorem coe_iInf₂ [DecidableRel (α := α) (· ≤ ·)] (f : ∀ i, κ i → Interval α) : ↑(⨅ (i) (j), f i j) = ⋂ (i) (j), (f i j : Set α) := by simp_rw [coe_iInf] end CompleteLattice diff --git a/Mathlib/Order/Interval/Finset/Box.lean b/Mathlib/Order/Interval/Finset/Box.lean index 1d5823025b14e..c84087a315416 100644 --- a/Mathlib/Order/Interval/Finset/Box.lean +++ b/Mathlib/Order/Interval/Finset/Box.lean @@ -62,7 +62,7 @@ open Finset namespace Prod variable {α β : Type*} [OrderedRing α] [OrderedRing β] [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [DecidableEq α] [DecidableEq β] [@DecidableRel (α × β) (· ≤ ·)] + [DecidableEq α] [DecidableEq β] [DecidableRel (α := α × β) (· ≤ ·)] @[simp] lemma card_box_succ (n : ℕ) : #(box (n + 1) : Finset (α × β)) = @@ -93,11 +93,6 @@ lemma card_box : ∀ {n}, n ≠ 0 → #(box n : Finset (ℤ × ℤ)) = 8 * n | 0 => by simp [Prod.ext_iff] | n + 1 => by simp [box_succ_eq_sdiff, Prod.le_def] - #adaptation_note /-- v4.7.0-rc1: `omega` no longer identifies atoms up to defeq. - (This had become a performance bottleneck.) - We need a tactic for normalising instances, to avoid the `have`/`simp` dance below: -/ - have : @Nat.cast ℤ instNatCastInt n = @Nat.cast ℤ AddMonoidWithOne.toNatCast n := rfl - simp only [this] omega -- TODO: Can this be generalised to locally finite archimedean ordered rings? diff --git a/Mathlib/Order/Interval/Finset/Defs.lean b/Mathlib/Order/Interval/Finset/Defs.lean index 730bf99b5e958..5ca55dc50e9eb 100644 --- a/Mathlib/Order/Interval/Finset/Defs.lean +++ b/Mathlib/Order/Interval/Finset/Defs.lean @@ -590,8 +590,8 @@ noncomputable def LocallyFiniteOrder.ofFiniteIcc (h : ∀ a b : α, (Set.Icc a b This is not an instance as it would not be defeq to better instances such as `Fin.locallyFiniteOrder`. -/ -abbrev Fintype.toLocallyFiniteOrder [Fintype α] [@DecidableRel α (· < ·)] - [@DecidableRel α (· ≤ ·)] : LocallyFiniteOrder α where +abbrev Fintype.toLocallyFiniteOrder [Fintype α] [DecidableRel (α := α) (· < ·)] + [DecidableRel (α := α) (· ≤ ·)] : LocallyFiniteOrder α where finsetIcc a b := (Set.Icc a b).toFinset finsetIco a b := (Set.Ico a b).toFinset finsetIoc a b := (Set.Ioc a b).toFinset @@ -790,7 +790,7 @@ end LocallyFiniteOrderTop /-! ### `Prod` -/ section LocallyFiniteOrder -variable [LocallyFiniteOrder α] [LocallyFiniteOrder β] [@DecidableRel (α × β) (· ≤ ·)] +variable [LocallyFiniteOrder α] [LocallyFiniteOrder β] [DecidableRel (α := α × β) (· ≤ ·)] instance Prod.instLocallyFiniteOrder : LocallyFiniteOrder (α × β) := LocallyFiniteOrder.ofIcc' (α × β) (fun x y ↦ Icc x.1 y.1 ×ˢ Icc x.2 y.2) fun a b x => by @@ -807,7 +807,7 @@ lemma Finset.card_Icc_prod (x y : α × β) : #(Icc x y) = #(Icc x.1 y.1) * #(Ic end LocallyFiniteOrder section LocallyFiniteOrderTop -variable [LocallyFiniteOrderTop α] [LocallyFiniteOrderTop β] [@DecidableRel (α × β) (· ≤ ·)] +variable [LocallyFiniteOrderTop α] [LocallyFiniteOrderTop β] [DecidableRel (α := α × β) (· ≤ ·)] instance Prod.instLocallyFiniteOrderTop : LocallyFiniteOrderTop (α × β) := LocallyFiniteOrderTop.ofIci' (α × β) (fun x => Ici x.1 ×ˢ Ici x.2) fun a x => by @@ -821,7 +821,7 @@ lemma Finset.card_Ici_prod (x : α × β) : #(Ici x) = #(Ici x.1) * #(Ici x.2) : end LocallyFiniteOrderTop section LocallyFiniteOrderBot -variable [LocallyFiniteOrderBot α] [LocallyFiniteOrderBot β] [@DecidableRel (α × β) (· ≤ ·)] +variable [LocallyFiniteOrderBot α] [LocallyFiniteOrderBot β] [DecidableRel (α := α × β) (· ≤ ·)] instance Prod.instLocallyFiniteOrderBot : LocallyFiniteOrderBot (α × β) := LocallyFiniteOrderBot.ofIic' (α × β) (fun x ↦ Iic x.1 ×ˢ Iic x.2) fun a x ↦ by @@ -836,7 +836,7 @@ end Preorder section Lattice variable [Lattice α] [Lattice β] [LocallyFiniteOrder α] [LocallyFiniteOrder β] - [@DecidableRel (α × β) (· ≤ ·)] + [DecidableRel (α := α × β) (· ≤ ·)] lemma Finset.uIcc_prod_def (x y : α × β) : uIcc x y = uIcc x.1 y.1 ×ˢ uIcc x.2 y.2 := rfl diff --git a/Mathlib/Order/KrullDimension.lean b/Mathlib/Order/KrullDimension.lean index 1b435cca65877..a6ba1d3f81334 100644 --- a/Mathlib/Order/KrullDimension.lean +++ b/Mathlib/Order/KrullDimension.lean @@ -750,7 +750,7 @@ lemma krullDim_int : krullDim ℤ = ⊤ := krullDim_of_noMaxOrder .. exact compare_gt_iff_gt.mp rfl) step := fun i => by simpa [WithBot.unbot_lt_iff] using p.step ⟨i + 1, by omega⟩ } have hlast' : p'.last = x := by - simp only [RelSeries.last, Fin.val_last, WithBot.unbot_eq_iff, ← hlast, Fin.last] + simp only [p', RelSeries.last, Fin.val_last, WithBot.unbot_eq_iff, ← hlast, Fin.last] congr omega suffices p'.length ≤ height p'.last by @@ -780,7 +780,7 @@ lemma krullDim_int : krullDim ℤ = ⊤ := krullDim_of_noMaxOrder .. simp [hlast]) step := fun i => by simpa only [WithTop.untop_lt_iff, WithTop.coe_untop] using p.step i } have hlast' : p'.last = x := by - simp only [RelSeries.last, Fin.val_last, WithTop.untop_eq_iff, ← hlast] + simp only [p', RelSeries.last, Fin.val_last, WithTop.untop_eq_iff, ← hlast] suffices p'.length ≤ height p'.last by rw [hlast'] at this simpa [p'] using this diff --git a/Mathlib/Order/OmegaCompletePartialOrder.lean b/Mathlib/Order/OmegaCompletePartialOrder.lean index c34eaa969055e..9e76dd904111b 100644 --- a/Mathlib/Order/OmegaCompletePartialOrder.lean +++ b/Mathlib/Order/OmegaCompletePartialOrder.lean @@ -296,8 +296,7 @@ lemma ωScottContinuous.comp (hg : ωScottContinuous g) (hf : ωScottContinuous lemma ωScottContinuous.const {x : β} : ωScottContinuous (Function.const α x) := by simp [ωScottContinuous, ScottContinuousOn, Set.range_nonempty] -set_option linter.deprecated false - +set_option linter.deprecated false in /-- A monotone function `f : α →o β` is continuous if it distributes over ωSup. In order to distinguish it from the (more commonly used) continuity from topology @@ -308,6 +307,7 @@ in Scott topological spaces (not defined here). -/ def Continuous (f : α →o β) : Prop := ∀ c : Chain α, f (ωSup c) = ωSup (c.map f) +set_option linter.deprecated false in /-- `Continuous' f` asserts that `f` is both monotone and continuous. -/ @[deprecated ωScottContinuous (since := "2024-05-29")] def Continuous' (f : α → β) : Prop := @@ -318,6 +318,7 @@ lemma isLUB_of_scottContinuous {c : Chain α} {f : α → β} (hf : ScottContinu IsLUB (Set.range (Chain.map c ⟨f, (ScottContinuous.monotone hf)⟩)) (f (ωSup c)) := ωScottContinuous.isLUB hf.scottContinuousOn +set_option linter.deprecated false in @[deprecated ScottContinuous.ωScottContinuous (since := "2024-05-29")] lemma ScottContinuous.continuous' {f : α → β} (hf : ScottContinuous f) : Continuous' f := by constructor @@ -325,45 +326,55 @@ lemma ScottContinuous.continuous' {f : α → β} (hf : ScottContinuous f) : Con rw [← (ωSup_eq_of_isLUB (isLUB_of_scottContinuous hf))] simp only [OrderHom.coe_mk] +set_option linter.deprecated false in @[deprecated ωScottContinuous.monotone (since := "2024-05-29")] theorem Continuous'.to_monotone {f : α → β} (hf : Continuous' f) : Monotone f := hf.fst +set_option linter.deprecated false in @[deprecated ωScottContinuous.of_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous.of_bundled (f : α → β) (hf : Monotone f) (hf' : Continuous ⟨f, hf⟩) : Continuous' f := ⟨hf, hf'⟩ +set_option linter.deprecated false in @[deprecated ωScottContinuous.of_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous.of_bundled' (f : α →o β) (hf' : Continuous f) : Continuous' f := ⟨f.mono, hf'⟩ +set_option linter.deprecated false in @[deprecated ωScottContinuous_iff_monotone_map_ωSup (since := "2024-05-29")] theorem Continuous'.to_bundled (f : α → β) (hf : Continuous' f) : Continuous ⟨f, hf.to_monotone⟩ := hf.snd +set_option linter.deprecated false in @[simp, norm_cast, deprecated ωScottContinuous_iff_monotone_map_ωSup (since := "2024-05-29")] theorem continuous'_coe : ∀ {f : α →o β}, Continuous' f ↔ Continuous f | ⟨_, hf⟩ => ⟨fun ⟨_, hc⟩ => hc, fun hc => ⟨hf, hc⟩⟩ variable (f : α →o β) (g : β →o γ) +set_option linter.deprecated false in @[deprecated ωScottContinuous.id (since := "2024-05-29")] theorem continuous_id : Continuous (@OrderHom.id α _) := by intro c; rw [c.map_id]; rfl +set_option linter.deprecated false in @[deprecated ωScottContinuous.comp (since := "2024-05-29")] theorem continuous_comp (hfc : Continuous f) (hgc : Continuous g) : Continuous (g.comp f) := by dsimp [Continuous] at *; intro rw [hfc, hgc, Chain.map_comp] +set_option linter.deprecated false in @[deprecated ωScottContinuous.id (since := "2024-05-29")] theorem id_continuous' : Continuous' (@id α) := continuous_id.of_bundled' _ +set_option linter.deprecated false in @[deprecated ωScottContinuous.const (since := "2024-05-29")] theorem continuous_const (x : β) : Continuous (OrderHom.const α x) := fun c => eq_of_forall_ge_iff fun z => by rw [ωSup_le_iff, Chain.map_coe, OrderHom.const_coe_coe]; simp +set_option linter.deprecated false in @[deprecated ωScottContinuous.const (since := "2024-05-29")] theorem const_continuous' (x : β) : Continuous' (Function.const α x) := Continuous.of_bundled' (OrderHom.const α x) (continuous_const x) @@ -484,13 +495,13 @@ lemma ωScottContinuous.of_apply₂ (hf : ∀ a, ωScottContinuous (f · a)) : lemma ωScottContinuous_iff_apply₂ : ωScottContinuous f ↔ ∀ a, ωScottContinuous (f · a) := ⟨ωScottContinuous.apply₂, ωScottContinuous.of_apply₂⟩ -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated ωScottContinuous.apply₂ (since := "2024-05-29")] theorem flip₁_continuous' (f : ∀ x : α, γ → β x) (a : α) (hf : Continuous' fun x y => f y x) : Continuous' (f a) := Continuous.of_bundled _ (fun _ _ h => hf.to_monotone h a) fun c => congr_fun (hf.to_bundled _ c) a +set_option linter.deprecated false in @[deprecated ωScottContinuous.of_apply₂ (since := "2024-05-29")] theorem flip₂_continuous' (f : γ → ∀ x, β x) (hf : ∀ x, Continuous' fun g => f g x) : Continuous' f := @@ -571,8 +582,7 @@ lemma ωScottContinuous.top : ωScottContinuous (⊤ : α → β) := lemma ωScottContinuous.bot : ωScottContinuous (⊥ : α → β) := by rw [← sSup_empty]; exact ωScottContinuous.sSup (by simp) -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated ωScottContinuous.sSup (since := "2024-05-29")] theorem sSup_continuous (s : Set <| α →o β) (hs : ∀ f ∈ s, Continuous f) : Continuous (sSup s) := by intro c @@ -582,11 +592,13 @@ theorem sSup_continuous (s : Set <| α →o β) (hs : ∀ f ∈ s, Continuous f) simpa (config := { contextual := true }) [ωSup_le_iff, hs _ _ _] using this exact ⟨fun H n f hf => H f hf n, fun H f hf n => H n f hf⟩ +set_option linter.deprecated false in @[deprecated ωScottContinuous.iSup (since := "2024-05-29")] theorem iSup_continuous {ι : Sort*} {f : ι → α →o β} (h : ∀ i, Continuous (f i)) : Continuous (⨆ i, f i) := sSup_continuous _ <| Set.forall_mem_range.2 h +set_option linter.deprecated false in @[deprecated ωScottContinuous.sSup (since := "2024-05-29")] theorem sSup_continuous' (s : Set (α → β)) (hc : ∀ f ∈ s, Continuous' f) : Continuous' (sSup s) := by @@ -596,18 +608,21 @@ theorem sSup_continuous' (s : Set (α → β)) (hc : ∀ f ∈ s, Continuous' f) norm_cast exact iSup_continuous fun f ↦ iSup_continuous fun hf ↦ hc hf +set_option linter.deprecated false in @[deprecated ωScottContinuous.sup (since := "2024-05-29")] theorem sup_continuous {f g : α →o β} (hf : Continuous f) (hg : Continuous g) : Continuous (f ⊔ g) := by rw [← sSup_pair]; apply sSup_continuous rintro f (rfl | rfl | _) <;> assumption +set_option linter.deprecated false in @[deprecated ωScottContinuous.top (since := "2024-05-29")] theorem top_continuous : Continuous (⊤ : α →o β) := by intro c; apply eq_of_forall_ge_iff; intro z simp only [OrderHom.instTopOrderHom_top, OrderHom.const_coe_coe, Function.const, top_le_iff, ωSup_le_iff, Chain.map_coe, Function.comp, forall_const] +set_option linter.deprecated false in @[deprecated ωScottContinuous.bot (since := "2024-05-29")] theorem bot_continuous : Continuous (⊥ : α →o β) := by rw [← sSup_empty] @@ -635,8 +650,7 @@ lemma ωScottContinuous.inf (hf : ωScottContinuous f) (hg : ωScottContinuous g (h (max j i)).imp (le_trans <| hf.monotone <| c.mono <| le_max_left _ _) (le_trans <| hg.monotone <| c.mono <| le_max_right _ _)⟩ -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated ωScottContinuous.inf (since := "2024-05-29")] theorem inf_continuous (f g : α →o β) (hf : Continuous f) (hg : Continuous g) : Continuous (f ⊓ g) := by @@ -647,6 +661,7 @@ theorem inf_continuous (f g : α →o β) (hf : Continuous f) (hg : Continuous g (h (max j i)).imp (le_trans <| f.mono <| c.mono <| le_max_left _ _) (le_trans <| g.mono <| c.mono <| le_max_right _ _)⟩ +set_option linter.deprecated false in @[deprecated ωScottContinuous.inf (since := "2024-05-29")] theorem inf_continuous' {f g : α → β} (hf : Continuous' f) (hg : Continuous' g) : Continuous' (f ⊓ g) := @@ -779,8 +794,7 @@ lemma ωScottContinuous.seq {β γ} {f : α → Part (β → γ)} {g : α → Pa simp only [seq_eq_bind_map] exact ωScottContinuous.bind hf <| ωScottContinuous.of_apply₂ fun _ ↦ ωScottContinuous.map hg -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated ωScottContinuous.bind (since := "2024-05-29")] theorem bind_continuous' {β γ : Type v} (f : α → Part β) (g : α → β → Part γ) : Continuous' f → Continuous' g → Continuous' fun x => f x >>= g x @@ -788,11 +802,13 @@ theorem bind_continuous' {β γ : Type v} (f : α → Part β) (g : α → β Continuous.of_bundled' (OrderHom.partBind ⟨f, hf⟩ ⟨g, hg⟩) (by intro c; rw [ωSup_bind, ← hf', ← hg']; rfl) +set_option linter.deprecated false in @[deprecated ωScottContinuous.map (since := "2024-05-29")] theorem map_continuous' {β γ : Type v} (f : β → γ) (g : α → Part β) (hg : Continuous' g) : Continuous' fun x => f <$> g x := by simp only [map_eq_bind_pure_comp]; apply bind_continuous' _ _ hg; apply const_continuous' +set_option linter.deprecated false in @[deprecated ωScottContinuous.seq (since := "2024-05-29")] theorem seq_continuous' {β γ : Type v} (f : α → Part (β → γ)) (g : α → Part β) (hf : Continuous' f) (hg : Continuous' g) : Continuous' fun x => f x <*> g x := by @@ -802,8 +818,6 @@ theorem seq_continuous' {β γ : Type v} (f : α → Part (β → γ)) (g : α intro apply map_continuous' _ _ hg -set_option linter.deprecated true - theorem continuous (F : α →𝒄 β) (C : Chain α) : F (ωSup C) = ωSup (C.map F) := F.ωScottContinuous.map_ωSup _ diff --git a/Mathlib/Order/SuccPred/Archimedean.lean b/Mathlib/Order/SuccPred/Archimedean.lean index d016540491343..0c89e2ea37b84 100644 --- a/Mathlib/Order/SuccPred/Archimedean.lean +++ b/Mathlib/Order/SuccPred/Archimedean.lean @@ -130,8 +130,8 @@ This isn't an instance due to a loop with `LinearOrder`. -/ -- See note [reducible non instances] abbrev IsSuccArchimedean.linearOrder [SuccOrder α] [IsSuccArchimedean α] - [DecidableEq α] [@DecidableRel α (· ≤ ·)] [@DecidableRel α (· < ·)] [IsDirected α (· ≥ ·)] : - LinearOrder α where + [DecidableEq α] [DecidableRel (α := α) (· ≤ ·)] [DecidableRel (α := α) (· < ·)] + [IsDirected α (· ≥ ·)] : LinearOrder α where le_total a b := have ⟨c, ha, hb⟩ := directed_of (· ≥ ·) a b le_total_of_codirected ha hb @@ -152,8 +152,8 @@ This isn't an instance due to a loop with `LinearOrder`. -/ -- See note [reducible non instances] abbrev IsPredArchimedean.linearOrder [PredOrder α] [IsPredArchimedean α] - [DecidableEq α] [@DecidableRel α (· ≤ ·)] [@DecidableRel α (· < ·)] [IsDirected α (· ≤ ·)] : - LinearOrder α := + [DecidableEq α] [DecidableRel (α := α) (· ≤ ·)] [DecidableRel (α := α) (· < ·)] + [IsDirected α (· ≤ ·)] : LinearOrder α := letI : LinearOrder αᵒᵈ := IsSuccArchimedean.linearOrder inferInstanceAs (LinearOrder αᵒᵈᵒᵈ) diff --git a/Mathlib/Order/SuccPred/Basic.lean b/Mathlib/Order/SuccPred/Basic.lean index ac3781d7a4350..bc0ce11ce535b 100644 --- a/Mathlib/Order/SuccPred/Basic.lean +++ b/Mathlib/Order/SuccPred/Basic.lean @@ -339,7 +339,7 @@ lemma succ_eq_of_covBy (h : a ⋖ b) : succ a = b := (succ_le_of_lt h.lt).antisy alias _root_.CovBy.succ_eq := succ_eq_of_covBy -theorem _root_.OrderIso.map_succ {β : Type*} [PartialOrder β] [SuccOrder β] (f : α ≃o β) (a : α) : +theorem _root_.OrderIso.map_succ [PartialOrder β] [SuccOrder β] (f : α ≃o β) (a : α) : f (succ a) = succ (f a) := by by_cases h : IsMax a · rw [h.succ_eq, (f.isMax_apply.2 h).succ_eq] diff --git a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean index c8ab06d7b669a..748703d2d7787 100644 --- a/Mathlib/Order/SuccPred/CompleteLinearOrder.lean +++ b/Mathlib/Order/SuccPred/CompleteLinearOrder.lean @@ -11,7 +11,7 @@ import Mathlib.Order.SuccPred.Limit -/ -open Order +open Order Set variable {ι α : Type*} @@ -19,8 +19,7 @@ section ConditionallyCompleteLinearOrder variable [ConditionallyCompleteLinearOrder α] [Nonempty ι] {f : ι → α} {s : Set α} {x : α} lemma csSup_mem_of_not_isSuccPrelimit - (hne : s.Nonempty) (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (sSup s)) : - sSup s ∈ s := by + (hne : s.Nonempty) (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (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 @@ -29,8 +28,7 @@ lemma csSup_mem_of_not_isSuccPrelimit alias csSup_mem_of_not_isSuccLimit := csSup_mem_of_not_isSuccPrelimit lemma csInf_mem_of_not_isPredPrelimit - (hne : s.Nonempty) (hbdd : BddBelow s) (hlim : ¬ IsPredPrelimit (sInf s)) : - sInf s ∈ s := by + (hne : s.Nonempty) (hbdd : BddBelow s) (hlim : ¬ IsPredPrelimit (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 @@ -39,17 +37,15 @@ lemma csInf_mem_of_not_isPredPrelimit alias csInf_mem_of_not_isPredLimit := csInf_mem_of_not_isPredPrelimit lemma exists_eq_ciSup_of_not_isSuccPrelimit - (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : - ∃ i, f i = ⨆ i, f i := - csSup_mem_of_not_isSuccPrelimit (Set.range_nonempty f) hf hf' + (hf : BddAbove (range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : ∃ i, f i = ⨆ i, f i := + csSup_mem_of_not_isSuccPrelimit (range_nonempty f) hf hf' @[deprecated exists_eq_ciSup_of_not_isSuccPrelimit (since := "2024-09-05")] alias exists_eq_ciSup_of_not_isSuccLimit := exists_eq_ciSup_of_not_isSuccPrelimit lemma exists_eq_ciInf_of_not_isPredPrelimit - (hf : BddBelow (Set.range f)) (hf' : ¬ IsPredPrelimit (⨅ i, f i)) : - ∃ i, f i = ⨅ i, f i := - csInf_mem_of_not_isPredPrelimit (Set.range_nonempty f) hf hf' + (hf : BddBelow (range f)) (hf' : ¬ IsPredPrelimit (⨅ i, f i)) : ∃ i, f i = ⨅ i, f i := + csInf_mem_of_not_isPredPrelimit (range_nonempty f) hf hf' @[deprecated exists_eq_ciInf_of_not_isPredPrelimit (since := "2024-09-05")] alias exists_eq_ciInf_of_not_isPredLimit := exists_eq_ciInf_of_not_isPredPrelimit @@ -69,15 +65,15 @@ lemma IsGLB.mem_of_nonempty_of_not_isPredPrelimit alias IsGLB.mem_of_nonempty_of_not_isPredLimit := IsGLB.mem_of_nonempty_of_not_isPredPrelimit lemma IsLUB.exists_of_nonempty_of_not_isSuccPrelimit - (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccPrelimit x) : - ∃ i, f i = x := hf.mem_of_nonempty_of_not_isSuccPrelimit (Set.range_nonempty f) hx + (hf : IsLUB (range f) x) (hx : ¬ IsSuccPrelimit x) : ∃ i, f i = x := + hf.mem_of_nonempty_of_not_isSuccPrelimit (range_nonempty f) hx @[deprecated IsLUB.exists_of_nonempty_of_not_isSuccPrelimit (since := "2024-09-05")] alias IsLUB.exists_of_nonempty_of_not_isSuccLimit := IsLUB.exists_of_nonempty_of_not_isSuccPrelimit lemma IsGLB.exists_of_nonempty_of_not_isPredPrelimit - (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredPrelimit x) : - ∃ i, f i = x := hf.mem_of_nonempty_of_not_isPredPrelimit (Set.range_nonempty f) hx + (hf : IsGLB (range f) x) (hx : ¬ IsPredPrelimit x) : ∃ i, f i = x := + hf.mem_of_nonempty_of_not_isPredPrelimit (range_nonempty f) hx @[deprecated IsGLB.exists_of_nonempty_of_not_isPredPrelimit (since := "2024-09-05")] alias IsGLB.exists_of_nonempty_of_not_isPredLimit := IsGLB.exists_of_nonempty_of_not_isPredPrelimit @@ -110,9 +106,8 @@ variable [ConditionallyCompleteLinearOrderBot α] {f : ι → α} {s : Set α} { /-- See `csSup_mem_of_not_isSuccPrelimit` for the `ConditionallyCompleteLinearOrder` version. -/ lemma csSup_mem_of_not_isSuccPrelimit' - (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (sSup s)) : - sSup s ∈ s := by - obtain (rfl|hs) := s.eq_empty_or_nonempty + (hbdd : BddAbove s) (hlim : ¬ IsSuccPrelimit (sSup s)) : sSup s ∈ s := by + obtain rfl | hs := s.eq_empty_or_nonempty · simp [isSuccPrelimit_bot] at hlim · exact csSup_mem_of_not_isSuccPrelimit hs hbdd hlim @@ -122,35 +117,59 @@ alias csSup_mem_of_not_isSuccLimit' := csSup_mem_of_not_isSuccPrelimit' /-- See `exists_eq_ciSup_of_not_isSuccPrelimit` for the `ConditionallyCompleteLinearOrder` version. -/ lemma exists_eq_ciSup_of_not_isSuccPrelimit' - (hf : BddAbove (Set.range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : - ∃ i, f i = ⨆ i, f i := + (hf : BddAbove (range f)) (hf' : ¬ IsSuccPrelimit (⨆ i, f i)) : ∃ i, f i = ⨆ i, f i := csSup_mem_of_not_isSuccPrelimit' hf hf' @[deprecated exists_eq_ciSup_of_not_isSuccPrelimit' (since := "2024-09-05")] alias exists_eq_ciSup_of_not_isSuccLimit' := exists_eq_ciSup_of_not_isSuccPrelimit' -lemma IsLUB.mem_of_not_isSuccPrelimit (hs : IsLUB s x) (hx : ¬ IsSuccPrelimit x) : - x ∈ s := by - obtain (rfl|hs') := s.eq_empty_or_nonempty +lemma IsLUB.mem_of_not_isSuccPrelimit (hs : IsLUB s x) (hx : ¬ IsSuccPrelimit x) : x ∈ s := by + obtain rfl | hs' := s.eq_empty_or_nonempty · simp [show x = ⊥ by simpa using hs, isSuccPrelimit_bot] at hx · exact hs.mem_of_nonempty_of_not_isSuccPrelimit hs' hx @[deprecated IsLUB.mem_of_not_isSuccPrelimit (since := "2024-09-05")] alias IsLUB.mem_of_not_isSuccLimit := IsLUB.mem_of_not_isSuccPrelimit -lemma IsLUB.exists_of_not_isSuccPrelimit (hf : IsLUB (Set.range f) x) (hx : ¬ IsSuccPrelimit x) : - ∃ i, f i = x := hf.mem_of_not_isSuccPrelimit hx +lemma IsLUB.exists_of_not_isSuccPrelimit (hf : IsLUB (range f) x) (hx : ¬ IsSuccPrelimit x) : + ∃ i, f i = x := + hf.mem_of_not_isSuccPrelimit hx @[deprecated IsLUB.exists_of_not_isSuccPrelimit (since := "2024-09-05")] alias IsLUB.exists_of_not_isSuccLimit := IsLUB.exists_of_not_isSuccPrelimit +theorem Order.IsSuccPrelimit.sSup_Iio (h : IsSuccPrelimit x) : sSup (Iio x) = x := by + obtain rfl | hx := eq_bot_or_bot_lt x + · simp + · refine (csSup_le ⟨⊥, hx⟩ fun a ha ↦ ha.le).antisymm <| le_of_forall_lt fun a ha ↦ ?_ + rw [lt_csSup_iff' bddAbove_Iio] + obtain ⟨b, hb', hb⟩ := (not_covBy_iff ha).1 (h a) + use b, hb + +theorem Order.IsSuccPrelimit.iSup_Iio (h : IsSuccPrelimit x) : ⨆ a : Iio x, a.1 = x := by + rw [← sSup_eq_iSup', h.sSup_Iio] + +theorem Order.IsSuccLimit.sSup_Iio (h : IsSuccLimit x) : sSup (Iio x) = x := + h.isSuccPrelimit.sSup_Iio + +theorem Order.IsSuccLimit.iSup_Iio (h : IsSuccLimit x) : ⨆ a : Iio x, a.1 = x := + h.isSuccPrelimit.iSup_Iio + +theorem sSup_Iio_eq_self_iff_isSuccPrelimit : sSup (Iio x) = x ↔ IsSuccPrelimit x := by + refine ⟨fun h ↦ ?_, IsSuccPrelimit.sSup_Iio⟩ + by_contra hx + rw [← h] at hx + simpa [h] using csSup_mem_of_not_isSuccPrelimit' bddAbove_Iio hx + +theorem iSup_Iio_eq_self_iff_isSuccPrelimit : ⨆ a : Iio x, a.1 = x ↔ IsSuccPrelimit x := by + rw [← sSup_eq_iSup', sSup_Iio_eq_self_iff_isSuccPrelimit] + end ConditionallyCompleteLinearOrderBot section CompleteLinearOrder variable [CompleteLinearOrder α] {s : Set α} {f : ι → α} {x : α} -lemma sSup_mem_of_not_isSuccPrelimit (hlim : ¬ IsSuccPrelimit (sSup s)) : - sSup s ∈ s := by +lemma sSup_mem_of_not_isSuccPrelimit (hlim : ¬ IsSuccPrelimit (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 @@ -158,8 +177,7 @@ lemma sSup_mem_of_not_isSuccPrelimit (hlim : ¬ IsSuccPrelimit (sSup s)) : @[deprecated sSup_mem_of_not_isSuccPrelimit (since := "2024-09-05")] alias sSup_mem_of_not_isSuccLimit := sSup_mem_of_not_isSuccPrelimit -lemma sInf_mem_of_not_isPredPrelimit (hlim : ¬ IsPredPrelimit (sInf s)) : - sInf s ∈ s := by +lemma sInf_mem_of_not_isPredPrelimit (hlim : ¬ IsPredPrelimit (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 @@ -181,15 +199,15 @@ lemma exists_eq_iInf_of_not_isPredPrelimit (hf : ¬ IsPredPrelimit (⨅ i, f i)) @[deprecated exists_eq_iInf_of_not_isPredPrelimit (since := "2024-09-05")] alias exists_eq_iInf_of_not_isPredLimit := exists_eq_iInf_of_not_isPredPrelimit -lemma IsGLB.mem_of_not_isPredPrelimit (hs : IsGLB s x) (hx : ¬ IsPredPrelimit x) : - x ∈ s := +lemma IsGLB.mem_of_not_isPredPrelimit (hs : IsGLB s x) (hx : ¬ IsPredPrelimit x) : x ∈ s := hs.sInf_eq ▸ sInf_mem_of_not_isPredPrelimit (hs.sInf_eq ▸ hx) @[deprecated IsGLB.mem_of_not_isPredPrelimit (since := "2024-09-05")] alias IsGLB.mem_of_not_isPredLimit := IsGLB.mem_of_not_isPredPrelimit -lemma IsGLB.exists_of_not_isPredPrelimit (hf : IsGLB (Set.range f) x) (hx : ¬ IsPredPrelimit x) : - ∃ i, f i = x := hf.mem_of_not_isPredPrelimit hx +lemma IsGLB.exists_of_not_isPredPrelimit (hf : IsGLB (range f) x) (hx : ¬ IsPredPrelimit x) : + ∃ i, f i = x := + hf.mem_of_not_isPredPrelimit hx @[deprecated IsGLB.exists_of_not_isPredPrelimit (since := "2024-09-05")] alias IsGLB.exists_of_not_isPredLimit := IsGLB.exists_of_not_isPredPrelimit diff --git a/Mathlib/Order/SuccPred/InitialSeg.lean b/Mathlib/Order/SuccPred/InitialSeg.lean new file mode 100644 index 0000000000000..46217a05da990 --- /dev/null +++ b/Mathlib/Order/SuccPred/InitialSeg.lean @@ -0,0 +1,79 @@ +/- +Copyright (c) 2024 Violeta Hernández Palacios. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Violeta Hernández Palacios +-/ +import Mathlib.Order.InitialSeg +import Mathlib.Order.SuccPred.Limit +import Mathlib.Order.UpperLower.Basic + +/-! +# Initial segments and successors + +We establish some connections between initial segment embeddings and successors and predecessors. +-/ + +variable {α β : Type*} {a b : α} [PartialOrder α] [PartialOrder β] + +open Order + +namespace InitialSeg + +@[simp] +theorem apply_covBy_apply_iff (f : α ≤i β) : f a ⋖ f b ↔ a ⋖ b := + (isLowerSet_range f).ordConnected.apply_covBy_apply_iff f.toOrderEmbedding + +@[simp] +theorem apply_wCovBy_apply_iff (f : α ≤i β) : f a ⩿ f b ↔ a ⩿ b := by + simp [wcovBy_iff_eq_or_covBy] + +theorem map_succ [SuccOrder α] [NoMaxOrder α] [SuccOrder β] (f : α ≤i β) (a : α) : + f (succ a) = succ (f a) := + (f.apply_covBy_apply_iff.2 (covBy_succ a)).succ_eq.symm + +theorem map_pred [PredOrder α] [NoMinOrder α] [PredOrder β] (f : α ≤i β) (a : α) : + f (pred a) = pred (f a) := + (f.apply_covBy_apply_iff.2 (pred_covBy a)).pred_eq.symm + +@[simp] +theorem isSuccPrelimit_apply_iff (f : α ≤i β) : IsSuccPrelimit (f a) ↔ IsSuccPrelimit a := by + constructor <;> intro h b hb + · rw [← f.apply_covBy_apply_iff] at hb + exact h _ hb + · obtain ⟨c, rfl⟩ := f.mem_range_of_rel hb.lt + rw [f.apply_covBy_apply_iff] at hb + exact h _ hb + +@[simp] +theorem isSuccLimit_apply_iff (f : α ≤i β) : IsSuccLimit (f a) ↔ IsSuccLimit a := by + simp [IsSuccLimit] + +end InitialSeg + +namespace PrincipalSeg + +@[simp] +theorem apply_covBy_apply_iff (f : α @@ -223,6 +226,12 @@ theorem mem_range_succ_or_isSuccPrelimit (a) : a ∈ range (succ : α → α) @[deprecated mem_range_succ_or_isSuccPrelimit (since := "2024-09-05")] alias mem_range_succ_or_isSuccLimit := mem_range_succ_or_isSuccPrelimit +theorem isMin_or_mem_range_succ_or_isSuccLimit (a) : + IsMin a ∨ a ∈ range (succ : α → α) ∨ IsSuccLimit a := by + rw [IsSuccLimit] + have := mem_range_succ_or_isSuccPrelimit a + tauto + theorem isSuccPrelimit_of_succ_lt (H : ∀ a < b, succ a < b) : IsSuccPrelimit b := fun a hab => (H a hab.lt).ne (CovBy.succ_eq hab) @@ -305,10 +314,24 @@ theorem IsSuccPrelimit.le_iff_forall_le (h : IsSuccPrelimit a) : a ≤ b ↔ ∀ by_contra! ha exact h b ⟨ha, fun c hb hc ↦ (H c hc).not_lt hb⟩ +theorem IsSuccLimit.le_iff_forall_le (h : IsSuccLimit a) : a ≤ b ↔ ∀ c < a, c ≤ b := + h.isSuccPrelimit.le_iff_forall_le + theorem IsSuccPrelimit.lt_iff_exists_lt (h : IsSuccPrelimit b) : a < b ↔ ∃ c < b, a < c := by rw [← not_iff_not] simp [h.le_iff_forall_le] +theorem IsSuccLimit.lt_iff_exists_lt (h : IsSuccLimit b) : a < b ↔ ∃ c < b, a < c := + h.isSuccPrelimit.lt_iff_exists_lt + +variable [SuccOrder α] + +theorem IsSuccPrelimit.le_succ_iff (hb : IsSuccPrelimit b) : b ≤ succ a ↔ b ≤ a := + le_iff_le_iff_lt_iff_lt.2 hb.succ_lt_iff + +theorem IsSuccLimit.le_succ_iff (hb : IsSuccLimit b) : b ≤ succ a ↔ b ≤ a := + hb.isSuccPrelimit.le_succ_iff + end LinearOrder /-! ### Predecessor limits -/ @@ -490,6 +513,9 @@ variable [PartialOrder α] theorem isPredLimit_iff [OrderTop α] : IsPredLimit a ↔ a ≠ ⊤ ∧ IsPredPrelimit a := by rw [IsPredLimit, isMax_iff_eq_top] +theorem IsPredLimit.lt_top [OrderTop α] (h : IsPredLimit a) : a < ⊤ := + h.ne_top.lt_top + variable [PredOrder α] theorem isPredPrelimit_of_pred_ne (h : ∀ b, pred b ≠ a) : IsPredPrelimit a := fun b hba => @@ -585,9 +611,23 @@ variable [LinearOrder α] theorem IsPredPrelimit.le_iff_forall_le (h : IsPredPrelimit a) : b ≤ a ↔ ∀ ⦃c⦄, a < c → b ≤ c := h.dual.le_iff_forall_le +theorem IsPredLimit.le_iff_forall_le (h : IsPredLimit a) : b ≤ a ↔ ∀ ⦃c⦄, a < c → b ≤ c := + h.dual.le_iff_forall_le + theorem IsPredPrelimit.lt_iff_exists_lt (h : IsPredPrelimit b) : b < a ↔ ∃ c, b < c ∧ c < a := h.dual.lt_iff_exists_lt +theorem IsPredLimit.lt_iff_exists_lt (h : IsPredLimit b) : b < a ↔ ∃ c, b < c ∧ c < a := + h.dual.lt_iff_exists_lt + +variable [PredOrder α] + +theorem IsPredPrelimit.pred_le_iff (hb : IsPredPrelimit b) : pred a ≤ b ↔ a ≤ b := + hb.dual.le_succ_iff + +theorem IsPredLimit.pred_le_iff (hb : IsPredLimit b) : pred a ≤ b ↔ a ≤ b := + hb.dual.le_succ_iff + end LinearOrder end Order diff --git a/Mathlib/Order/SupClosed.lean b/Mathlib/Order/SupClosed.lean index 84fdcccc76f9d..fdec9d591598c 100644 --- a/Mathlib/Order/SupClosed.lean +++ b/Mathlib/Order/SupClosed.lean @@ -7,6 +7,7 @@ import Mathlib.Data.Finset.Lattice.Fold import Mathlib.Data.Finset.Powerset import Mathlib.Data.Set.Finite.Basic import Mathlib.Order.Closure +import Mathlib.Order.ConditionallyCompleteLattice.Finset /-! # Sets closed under join/meet @@ -29,7 +30,7 @@ is automatically complete. All dually for `⊓`. greatest lower bound is automatically complete. -/ -variable {F α β : Type*} +variable {ι : Sort*} {F α β : Type*} section SemilatticeSup variable [SemilatticeSup α] [SemilatticeSup β] @@ -501,3 +502,66 @@ def SemilatticeInf.toCompleteSemilatticeInf [SemilatticeInf α] (sInf : Set α sInf := fun s => sInf (infClosure s) sInf_le _ _ ha := (h _ infClosed_infClosure).1 <| subset_infClosure ha le_sInf s a ha := (le_isGLB_iff <| h _ infClosed_infClosure).2 <| by rwa [lowerBounds_infClosure] + + +section ConditionallyCompleteLattice +variable [ConditionallyCompleteLattice α] {f : ι → α} {s t : Set α} + +lemma SupClosed.iSup_mem_of_nonempty [Finite ι] [Nonempty ι] (hs : SupClosed s) + (hf : ∀ i, f i ∈ s) : ⨆ i, f i ∈ s := by + cases nonempty_fintype (PLift ι) + rw [← iSup_plift_down, ← Finset.sup'_univ_eq_ciSup] + exact hs.finsetSup'_mem Finset.univ_nonempty fun _ _ ↦ hf _ + +lemma InfClosed.iInf_mem_of_nonempty [Finite ι] [Nonempty ι] (hs : InfClosed s) + (hf : ∀ i, f i ∈ s) : ⨅ i, f i ∈ s := hs.dual.iSup_mem_of_nonempty hf + +lemma SupClosed.sSup_mem_of_nonempty (hs : SupClosed s) (ht : t.Finite) (ht' : t.Nonempty) + (hts : t ⊆ s) : sSup t ∈ s := by + have := ht.to_subtype + have := ht'.to_subtype + rw [sSup_eq_iSup'] + exact hs.iSup_mem_of_nonempty (by simpa) + +lemma InfClosed.sInf_mem_of_nonempty (hs : InfClosed s) (ht : t.Finite) (ht' : t.Nonempty) + (hts : t ⊆ s) : sInf t ∈ s := hs.dual.sSup_mem_of_nonempty ht ht' hts + +end ConditionallyCompleteLattice + +variable [CompleteLattice α] {f : ι → α} {s t : Set α} + +lemma SupClosed.biSup_mem_of_nonempty {ι : Type*} {t : Set ι} {f : ι → α} (hs : SupClosed s) + (ht : t.Finite) (ht' : t.Nonempty) (hf : ∀ i ∈ t, f i ∈ s) : ⨆ i ∈ t, f i ∈ s := by + rw [← sSup_image] + exact hs.sSup_mem_of_nonempty (ht.image _) (by simpa) (by simpa) + +lemma InfClosed.biInf_mem_of_nonempty {ι : Type*} {t : Set ι} {f : ι → α} (hs : InfClosed s) + (ht : t.Finite) (ht' : t.Nonempty) (hf : ∀ i ∈ t, f i ∈ s) : ⨅ i ∈ t, f i ∈ s := + hs.dual.biSup_mem_of_nonempty ht ht' hf + +lemma SupClosed.iSup_mem [Finite ι] (hs : SupClosed s) (hbot : ⊥ ∈ s) (hf : ∀ i, f i ∈ s) : + ⨆ i, f i ∈ s := by + cases isEmpty_or_nonempty ι + · simpa [iSup_of_empty] + · exact hs.iSup_mem_of_nonempty hf + +lemma InfClosed.iInf_mem [Finite ι] (hs : InfClosed s) (htop : ⊤ ∈ s) (hf : ∀ i, f i ∈ s) : + ⨅ i, f i ∈ s := hs.dual.iSup_mem htop hf + +lemma SupClosed.sSup_mem (hs : SupClosed s) (ht : t.Finite) (hbot : ⊥ ∈ s) (hts : t ⊆ s) : + sSup t ∈ s := by + have := ht.to_subtype + rw [sSup_eq_iSup'] + exact hs.iSup_mem hbot (by simpa) + +lemma InfClosed.sInf_mem (hs : InfClosed s) (ht : t.Finite) (htop : ⊤ ∈ s) (hts : t ⊆ s) : + sInf t ∈ s := hs.dual.sSup_mem ht htop hts + +lemma SupClosed.biSup_mem {ι : Type*} {t : Set ι} {f : ι → α} (hs : SupClosed s) + (ht : t.Finite) (hbot : ⊥ ∈ s) (hf : ∀ i ∈ t, f i ∈ s) : ⨆ i ∈ t, f i ∈ s := by + rw [← sSup_image] + exact hs.sSup_mem (ht.image _) hbot (by simpa) + +lemma InfClosed.biInf_mem {ι : Type*} {t : Set ι} {f : ι → α} (hs : InfClosed s) + (ht : t.Finite) (htop : ⊤ ∈ s) (hf : ∀ i ∈ t, f i ∈ s) : ⨅ i ∈ t, f i ∈ s := + hs.dual.biSup_mem ht htop hf diff --git a/Mathlib/Order/TypeTags.lean b/Mathlib/Order/TypeTags.lean index 2c8dee9aa90c8..430818ad4338e 100644 --- a/Mathlib/Order/TypeTags.lean +++ b/Mathlib/Order/TypeTags.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Simon Hudon, Yury Kudryashov -/ import Mathlib.Order.Notation -import Mathlib.Data.Nat.Notation /-! # Order-related type synonyms @@ -103,49 +102,3 @@ theorem recTopCoe_coe {C : WithTop α → Sort*} (d : C ⊤) (f : ∀ a : α, C rfl end WithTop - -/-- Extended natural numbers `ℕ∞ = WithTop ℕ`. -/ -def ENat : Type := WithTop ℕ deriving Top, Inhabited - -@[inherit_doc] notation "ℕ∞" => ENat - -namespace ENat - -instance instNatCast : NatCast ℕ∞ := ⟨WithTop.some⟩ - --- Porting note (https://github.com/leanprover-community/mathlib4/issues/11445): new definition copied from `WithTop` -/-- Recursor for `ENat` using the preferred forms `⊤` and `↑a`. -/ -@[elab_as_elim, induction_eliminator, cases_eliminator] -def recTopCoe {C : ℕ∞ → Sort*} (top : C ⊤) (coe : ∀ a : ℕ, C a) : ∀ n : ℕ∞, C n - | none => top - | Option.some a => coe a - -@[simp] -theorem recTopCoe_top {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) : - @recTopCoe C d f ⊤ = d := - rfl - -@[simp] -theorem recTopCoe_coe {C : ℕ∞ → Sort*} (d : C ⊤) (f : ∀ a : ℕ, C a) (x : ℕ) : - @recTopCoe C d f ↑x = f x := - rfl - -end ENat - -/-- `ℕ+` is the type of positive natural numbers. It is defined as a subtype, - and the VM representation of `ℕ+` is the same as `ℕ` because the proof - is not stored. -/ -def PNat := { n : ℕ // 0 < n } deriving DecidableEq - -@[inherit_doc] -notation "ℕ+" => PNat - -/-- The underlying natural number -/ -@[coe] -def PNat.val : ℕ+ → ℕ := Subtype.val - -instance coePNatNat : Coe ℕ+ ℕ := - ⟨PNat.val⟩ - -instance : Repr ℕ+ := - ⟨fun n n' => reprPrec n.1 n'⟩ diff --git a/Mathlib/Order/WellFounded.lean b/Mathlib/Order/WellFounded.lean index cf572cbc31597..17b5c843b5ec7 100644 --- a/Mathlib/Order/WellFounded.lean +++ b/Mathlib/Order/WellFounded.lean @@ -88,21 +88,26 @@ protected theorem lt_sup {r : α → α → Prop} (wf : WellFounded r) {s : Set (hx : x ∈ s) : r x (wf.sup s h) := min_mem wf { x | ∀ a ∈ s, r a x } h x hx -section +section deprecated open Classical in +set_option linter.deprecated false in /-- A successor of an element `x` in a well-founded order is a minimal element `y` such that `x < y` if one exists. Otherwise it is `x` itself. -/ +@[deprecated "If you have a linear order, consider defining a `SuccOrder` instance through +`ConditionallyCompleteLinearOrder.toSuccOrder`." (since := "2024-10-25")] protected noncomputable def succ {r : α → α → Prop} (wf : WellFounded r) (x : α) : α := if h : ∃ y, r x y then wf.min { y | r x y } h else x +set_option linter.deprecated false in +@[deprecated "No deprecation message was provided." (since := "2024-10-25")] protected theorem lt_succ {r : α → α → Prop} (wf : WellFounded r) {x : α} (h : ∃ y, r x y) : r x (wf.succ x) := by rw [WellFounded.succ, dif_pos h] apply min_mem -end - +set_option linter.deprecated false in +@[deprecated "No deprecation message was provided." (since := "2024-10-25")] protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] {x : α} (h : ∃ y, r x y) (y : α) : r y (wo.wf.succ x) ↔ r y x ∨ y = x := by constructor @@ -120,6 +125,8 @@ protected theorem lt_succ_iff {r : α → α → Prop} [wo : IsWellOrder α r] { exact hy rintro (hy | rfl); (· exact _root_.trans hy (wo.wf.lt_succ h)); exact wo.wf.lt_succ h +end deprecated + end WellFounded section LinearOrder diff --git a/Mathlib/Order/WithBot.lean b/Mathlib/Order/WithBot.lean index da8552cf675af..7ceb5d577ecb0 100644 --- a/Mathlib/Order/WithBot.lean +++ b/Mathlib/Order/WithBot.lean @@ -445,13 +445,13 @@ instance distribLattice [DistribLattice α] : DistribLattice (WithBot α) := instance decidableEq [DecidableEq α] : DecidableEq (WithBot α) := inferInstanceAs <| DecidableEq (Option α) -instance decidableLE [LE α] [@DecidableRel α (· ≤ ·)] : @DecidableRel (WithBot α) (· ≤ ·) +instance decidableLE [LE α] [DecidableRel (α := α) (· ≤ ·)] : DecidableRel (α := WithBot α) (· ≤ ·) | none, _ => isTrue fun _ h => Option.noConfusion h | Option.some x, Option.some y => if h : x ≤ y then isTrue (coe_le_coe.2 h) else isFalse <| by simp [*] | Option.some x, none => isFalse fun h => by rcases h x rfl with ⟨y, ⟨_⟩, _⟩ -instance decidableLT [LT α] [@DecidableRel α (· < ·)] : @DecidableRel (WithBot α) (· < ·) +instance decidableLT [LT α] [DecidableRel (α := α) (· < ·)] : DecidableRel (α := WithBot α) (· < ·) | none, Option.some x => isTrue <| by exists x, rfl; rintro _ ⟨⟩ | Option.some x, Option.some y => if h : x < y then isTrue <| by simp [*] else isFalse <| by simp [*] @@ -1167,12 +1167,12 @@ instance distribLattice [DistribLattice α] : DistribLattice (WithTop α) := instance decidableEq [DecidableEq α] : DecidableEq (WithTop α) := inferInstanceAs <| DecidableEq (Option α) -instance decidableLE [LE α] [@DecidableRel α (· ≤ ·)] : - @DecidableRel (WithTop α) (· ≤ ·) := fun _ _ => +instance decidableLE [LE α] [DecidableRel (α := α) (· ≤ ·)] : + DecidableRel (α := WithTop α) (· ≤ ·) := fun _ _ => decidable_of_decidable_of_iff toDual_le_toDual_iff -instance decidableLT [LT α] [@DecidableRel α (· < ·)] : - @DecidableRel (WithTop α) (· < ·) := fun _ _ => +instance decidableLT [LT α] [DecidableRel (α := α) (· < ·)] : + DecidableRel (α := WithTop α) (· < ·) := fun _ _ => decidable_of_decidable_of_iff toDual_lt_toDual_iff instance isTotal_le [LE α] [IsTotal α (· ≤ ·)] : IsTotal (WithTop α) (· ≤ ·) := diff --git a/Mathlib/Order/Zorn.lean b/Mathlib/Order/Zorn.lean index b0418fa34a94b..833cc2e53c890 100644 --- a/Mathlib/Order/Zorn.lean +++ b/Mathlib/Order/Zorn.lean @@ -178,3 +178,23 @@ theorem IsChain.exists_maxChain (hc : IsChain r c) : ∃ M, @IsMaxChain _ r M cases' hcs₁ hsy hsz hsseq with h h · exact (hcs₀ hsz).right (h hysy) hzsz hyz · exact (hcs₀ hsy).right hysy (h hzsz) hyz + +/-! ### Flags -/ + +namespace Flag + +variable [Preorder α] {c : Set α} {s : Flag α} {a b : α} + +lemma _root_.IsChain.exists_subset_flag (hc : IsChain (· ≤ ·) c) : ∃ s : Flag α, c ⊆ s := + let ⟨s, hs, hcs⟩ := hc.exists_maxChain; ⟨ofIsMaxChain s hs, hcs⟩ + +lemma exists_mem (a : α) : ∃ s : Flag α, a ∈ s := + let ⟨s, hs⟩ := Set.subsingleton_singleton (a := a).isChain.exists_subset_flag + ⟨s, hs rfl⟩ + +lemma exists_mem_mem (hab : a ≤ b) : ∃ s : Flag α, a ∈ s ∧ b ∈ s := by + simpa [Set.insert_subset_iff] using (IsChain.pair hab).exists_subset_flag + +instance : Nonempty (Flag α) := ⟨.ofIsMaxChain _ maxChain_spec⟩ + +end Flag diff --git a/Mathlib/Probability/Kernel/Composition.lean b/Mathlib/Probability/Kernel/Composition/Basic.lean similarity index 98% rename from Mathlib/Probability/Kernel/Composition.lean rename to Mathlib/Probability/Kernel/Composition/Basic.lean index e3b9daa87e50a..a992511575a5d 100644 --- a/Mathlib/Probability/Kernel/Composition.lean +++ b/Mathlib/Probability/Kernel/Composition/Basic.lean @@ -726,6 +726,12 @@ instance IsMarkovKernel.comap (κ : Kernel α β) [IsMarkovKernel κ] (hg : Meas IsMarkovKernel (comap κ g hg) := ⟨fun a => ⟨by rw [comap_apply' κ hg a Set.univ, measure_univ]⟩⟩ +instance IsZeroOrMarkovKernel.comap (κ : Kernel α β) [IsZeroOrMarkovKernel κ] (hg : Measurable g) : + IsZeroOrMarkovKernel (comap κ g hg) := by + rcases eq_zero_or_isMarkovKernel κ with rfl | h + · simp only [comap_zero]; infer_instance + · have := IsMarkovKernel.comap κ hg; infer_instance + instance IsFiniteKernel.comap (κ : Kernel α β) [IsFiniteKernel κ] (hg : Measurable g) : IsFiniteKernel (comap κ g hg) := by refine ⟨⟨IsFiniteKernel.bound κ, IsFiniteKernel.bound_lt_top κ, fun a => ?_⟩⟩ @@ -802,6 +808,12 @@ instance IsMarkovKernel.prodMkLeft (κ : Kernel α β) [IsMarkovKernel κ] : instance IsMarkovKernel.prodMkRight (κ : Kernel α β) [IsMarkovKernel κ] : IsMarkovKernel (prodMkRight γ κ) := by rw [Kernel.prodMkRight]; infer_instance +instance IsZeroOrMarkovKernel.prodMkLeft (κ : Kernel α β) [IsZeroOrMarkovKernel κ] : + IsZeroOrMarkovKernel (prodMkLeft γ κ) := by rw [Kernel.prodMkLeft]; infer_instance + +instance IsZeroOrMarkovKernel.prodMkRight (κ : Kernel α β) [IsZeroOrMarkovKernel κ] : + IsZeroOrMarkovKernel (prodMkRight γ κ) := by rw [Kernel.prodMkRight]; infer_instance + instance IsFiniteKernel.prodMkLeft (κ : Kernel α β) [IsFiniteKernel κ] : IsFiniteKernel (prodMkLeft γ κ) := by rw [Kernel.prodMkLeft]; infer_instance diff --git a/Mathlib/Probability/Kernel/IntegralCompProd.lean b/Mathlib/Probability/Kernel/Composition/IntegralCompProd.lean similarity index 99% rename from Mathlib/Probability/Kernel/IntegralCompProd.lean rename to Mathlib/Probability/Kernel/Composition/IntegralCompProd.lean index e88e7a0f5f916..0fab071f69bea 100644 --- a/Mathlib/Probability/Kernel/IntegralCompProd.lean +++ b/Mathlib/Probability/Kernel/Composition/IntegralCompProd.lean @@ -3,7 +3,7 @@ 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.Probability.Kernel.Composition +import Mathlib.Probability.Kernel.Composition.Basic import Mathlib.MeasureTheory.Integral.SetIntegral /-! diff --git a/Mathlib/Probability/Kernel/MeasureCompProd.lean b/Mathlib/Probability/Kernel/Composition/MeasureCompProd.lean similarity index 63% rename from Mathlib/Probability/Kernel/MeasureCompProd.lean rename to Mathlib/Probability/Kernel/Composition/MeasureCompProd.lean index 9a7d41a2b61ca..b57ca2ef11459 100644 --- a/Mathlib/Probability/Kernel/MeasureCompProd.lean +++ b/Mathlib/Probability/Kernel/Composition/MeasureCompProd.lean @@ -3,7 +3,8 @@ 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.Probability.Kernel.IntegralCompProd +import Mathlib.MeasureTheory.Decomposition.Lebesgue +import Mathlib.Probability.Kernel.Composition.IntegralCompProd /-! # Composition-Product of a measure and a kernel @@ -200,7 +201,7 @@ instance [IsProbabilityMeasure μ] [IsMarkovKernel κ] : IsProbabilityMeasure ( section AbsolutelyContinuous -lemma absolutelyContinuous_compProd_left [SFinite ν] (hμν : μ ≪ ν) (κ : Kernel α β) : +lemma AbsolutelyContinuous.compProd_left [SFinite ν] (hμν : μ ≪ ν) (κ : Kernel α β) : μ ⊗ₘ κ ≪ ν ⊗ₘ κ := by by_cases hκ : IsSFiniteKernel κ · have : SFinite μ := sFinite_of_absolutelyContinuous hμν @@ -210,7 +211,10 @@ lemma absolutelyContinuous_compProd_left [SFinite ν] (hμν : μ ≪ ν) (κ : exact hμν.ae_eq hs_zero · simp [compProd_of_not_isSFiniteKernel _ _ hκ] -lemma absolutelyContinuous_compProd_right [SFinite μ] [IsSFiniteKernel η] +@[deprecated (since := "2024-12-11")] +alias absolutelyContinuous_compProd_left := AbsolutelyContinuous.compProd_left + +lemma AbsolutelyContinuous.compProd_right [SFinite μ] [IsSFiniteKernel η] (hκη : ∀ᵐ a ∂μ, κ a ≪ η a) : μ ⊗ₘ κ ≪ μ ⊗ₘ η := by by_cases hκ : IsSFiniteKernel κ @@ -220,12 +224,17 @@ lemma absolutelyContinuous_compProd_right [SFinite μ] [IsSFiniteKernel η] filter_upwards [hs_zero, hκη] with a ha_zero ha_ac using ha_ac ha_zero · simp [compProd_of_not_isSFiniteKernel _ _ hκ] -lemma absolutelyContinuous_compProd [SFinite ν] [IsSFiniteKernel η] +@[deprecated (since := "2024-12-11")] +alias absolutelyContinuous_compProd_right := AbsolutelyContinuous.compProd_right + +lemma AbsolutelyContinuous.compProd [SFinite ν] [IsSFiniteKernel η] (hμν : μ ≪ ν) (hκη : ∀ᵐ a ∂μ, κ a ≪ η a) : μ ⊗ₘ κ ≪ ν ⊗ₘ η := have : SFinite μ := sFinite_of_absolutelyContinuous hμν - (Measure.absolutelyContinuous_compProd_right hκη).trans - (Measure.absolutelyContinuous_compProd_left hμν _) + (Measure.AbsolutelyContinuous.compProd_right hκη).trans (hμν.compProd_left _) + +@[deprecated (since := "2024-12-11")] +alias absolutelyContinuous_compProd := AbsolutelyContinuous.compProd lemma absolutelyContinuous_of_compProd [SFinite μ] [IsSFiniteKernel κ] [h_zero : ∀ a, NeZero (κ a)] (h : μ ⊗ₘ κ ≪ ν ⊗ₘ η) : @@ -248,6 +257,109 @@ lemma absolutelyContinuous_of_compProd [SFinite μ] [IsSFiniteKernel κ] [h_zero simp only [Measure.measure_univ_eq_zero] exact (h_zero a).out +lemma absolutelyContinuous_compProd_left_iff [SFinite μ] [SFinite ν] + [IsFiniteKernel κ] [∀ a, NeZero (κ a)] : + μ ⊗ₘ κ ≪ ν ⊗ₘ κ ↔ μ ≪ ν := + ⟨absolutelyContinuous_of_compProd, fun h ↦ h.compProd_left κ⟩ + +lemma AbsolutelyContinuous.compProd_of_compProd [SFinite ν] [IsSFiniteKernel η] + (hμν : μ ≪ ν) (hκη : μ ⊗ₘ κ ≪ μ ⊗ₘ η) : + μ ⊗ₘ κ ≪ ν ⊗ₘ η := by + by_cases hμ : SFinite μ + swap; · rw [compProd_of_not_sfinite _ _ hμ]; simp + refine AbsolutelyContinuous.mk fun s hs hs_zero ↦ ?_ + suffices (μ ⊗ₘ η) s = 0 from hκη this + rw [measure_zero_iff_ae_nmem, ae_compProd_iff hs.compl] at hs_zero ⊢ + exact hμν.ae_le hs_zero + end AbsolutelyContinuous +section MutuallySingular + +lemma MutuallySingular.compProd_of_left (hμν : μ ⟂ₘ ν) (κ η : Kernel α β) : + μ ⊗ₘ κ ⟂ₘ ν ⊗ₘ η := by + by_cases hμ : SFinite μ + swap; · rw [compProd_of_not_sfinite _ _ hμ]; simp + by_cases hν : SFinite ν + swap; · rw [compProd_of_not_sfinite _ _ hν]; simp + by_cases hκ : IsSFiniteKernel κ + swap; · rw [compProd_of_not_isSFiniteKernel _ _ hκ]; simp + by_cases hη : IsSFiniteKernel η + swap; · rw [compProd_of_not_isSFiniteKernel _ _ hη]; simp + refine ⟨hμν.nullSet ×ˢ univ, hμν.measurableSet_nullSet.prod .univ, ?_⟩ + rw [compProd_apply_prod hμν.measurableSet_nullSet .univ, compl_prod_eq_union] + simp only [MutuallySingular.restrict_nullSet, lintegral_zero_measure, compl_univ, + prod_empty, union_empty, true_and] + rw [compProd_apply_prod hμν.measurableSet_nullSet.compl .univ] + simp + +lemma mutuallySingular_of_mutuallySingular_compProd {ξ : Measure α} + [SFinite μ] [SFinite ν] [IsSFiniteKernel κ] [IsSFiniteKernel η] + (h : μ ⊗ₘ κ ⟂ₘ ν ⊗ₘ η) (hμ : ξ ≪ μ) (hν : ξ ≪ ν) : + ∀ᵐ x ∂ξ, κ x ⟂ₘ η x := by + have hs : MeasurableSet h.nullSet := h.measurableSet_nullSet + have hμ_zero : (μ ⊗ₘ κ) h.nullSet = 0 := h.measure_nullSet + have hν_zero : (ν ⊗ₘ η) h.nullSetᶜ = 0 := h.measure_compl_nullSet + rw [compProd_apply, lintegral_eq_zero_iff'] at hμ_zero hν_zero + · filter_upwards [hμ hμ_zero, hν hν_zero] with x hxμ hxν + exact ⟨Prod.mk x ⁻¹' h.nullSet, measurable_prod_mk_left hs, ⟨hxμ, hxν⟩⟩ + · exact (Kernel.measurable_kernel_prod_mk_left hs.compl).aemeasurable + · exact (Kernel.measurable_kernel_prod_mk_left hs).aemeasurable + · exact hs.compl + · exact hs + +lemma mutuallySingular_compProd_left_iff [SFinite μ] [SigmaFinite ν] + [IsSFiniteKernel κ] [hκ : ∀ x, NeZero (κ x)] : + μ ⊗ₘ κ ⟂ₘ ν ⊗ₘ κ ↔ μ ⟂ₘ ν := by + refine ⟨fun h ↦ ?_, fun h ↦ h.compProd_of_left _ _⟩ + rw [← withDensity_rnDeriv_eq_zero] + have hh := mutuallySingular_of_mutuallySingular_compProd h ?_ ?_ + (ξ := ν.withDensity (μ.rnDeriv ν)) + rotate_left + · exact absolutelyContinuous_of_le (μ.withDensity_rnDeriv_le ν) + · exact withDensity_absolutelyContinuous _ _ + simp_rw [MutuallySingular.self_iff, (hκ _).ne] at hh + exact ae_eq_bot.mp (Filter.eventually_false_iff_eq_bot.mp hh) + +lemma AbsolutelyContinuous.mutuallySingular_compProd_iff [SigmaFinite μ] [SigmaFinite ν] + (hμν : μ ≪ ν) : + μ ⊗ₘ κ ⟂ₘ ν ⊗ₘ η ↔ μ ⊗ₘ κ ⟂ₘ μ ⊗ₘ η := by + conv_lhs => rw [ν.haveLebesgueDecomposition_add μ] + rw [compProd_add_left, MutuallySingular.add_right_iff] + simp only [(mutuallySingular_singularPart ν μ).symm.compProd_of_left κ η, true_and] + refine ⟨fun h ↦ h.mono_ac .rfl ?_, fun h ↦ h.mono_ac .rfl ?_⟩ + · exact (absolutelyContinuous_withDensity_rnDeriv hμν).compProd_left _ + · exact (withDensity_absolutelyContinuous μ (ν.rnDeriv μ)).compProd_left _ + +lemma mutuallySingular_compProd_iff [SigmaFinite μ] [SigmaFinite ν] : + μ ⊗ₘ κ ⟂ₘ ν ⊗ₘ η ↔ ∀ ξ, SFinite ξ → ξ ≪ μ → ξ ≪ ν → ξ ⊗ₘ κ ⟂ₘ ξ ⊗ₘ η := by + conv_lhs => rw [μ.haveLebesgueDecomposition_add ν] + rw [compProd_add_left, MutuallySingular.add_left_iff] + simp only [(mutuallySingular_singularPart μ ν).compProd_of_left κ η, true_and] + rw [(withDensity_absolutelyContinuous ν (μ.rnDeriv ν)).mutuallySingular_compProd_iff] + refine ⟨fun h ξ hξ hξμ hξν ↦ ?_, fun h ↦ ?_⟩ + · exact h.mono_ac ((hξμ.withDensity_rnDeriv hξν).compProd_left _) + ((hξμ.withDensity_rnDeriv hξν).compProd_left _) + · refine h _ ?_ ?_ ?_ + · infer_instance + · exact absolutelyContinuous_of_le (withDensity_rnDeriv_le _ _) + · exact withDensity_absolutelyContinuous ν (μ.rnDeriv ν) + +end MutuallySingular + +lemma absolutelyContinuous_compProd_of_compProd [SigmaFinite μ] [SigmaFinite ν] + (hκη : μ ⊗ₘ κ ≪ ν ⊗ₘ η) : + μ ⊗ₘ κ ≪ μ ⊗ₘ η := by + rw [ν.haveLebesgueDecomposition_add μ, compProd_add_left, add_comm] at hκη + have h := absolutelyContinuous_of_add_of_mutuallySingular hκη + ((mutuallySingular_singularPart _ _).symm.compProd_of_left _ _) + refine h.trans (AbsolutelyContinuous.compProd_left ?_ _) + exact withDensity_absolutelyContinuous _ _ + +lemma absolutelyContinuous_compProd_iff + [SigmaFinite μ] [SigmaFinite ν] [IsSFiniteKernel κ] [IsSFiniteKernel η] [∀ x, NeZero (κ x)] : + μ ⊗ₘ κ ≪ ν ⊗ₘ η ↔ μ ≪ ν ∧ μ ⊗ₘ κ ≪ μ ⊗ₘ η := + ⟨fun h ↦ ⟨absolutelyContinuous_of_compProd h, absolutelyContinuous_compProd_of_compProd h⟩, + fun h ↦ h.1.compProd_of_compProd h.2⟩ + end MeasureTheory.Measure diff --git a/Mathlib/Probability/Kernel/Composition/ParallelComp.lean b/Mathlib/Probability/Kernel/Composition/ParallelComp.lean new file mode 100644 index 0000000000000..ab8450cc02791 --- /dev/null +++ b/Mathlib/Probability/Kernel/Composition/ParallelComp.lean @@ -0,0 +1,118 @@ +/- +Copyright (c) 2024 Rémy Degenne. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Rémy Degenne, Lorenzo Luccioli +-/ +import Mathlib.Probability.Kernel.Composition.Basic + +/-! + +# Parallel composition of kernels + +Two kernels `κ : Kernel α β` and `η : Kernel γ δ` can be applied in parallel to give a kernel +`κ ∥ₖ η` from `α × γ` to `β × δ`: `(κ ∥ₖ η) (a, c) = (κ a).prod (η c)`. + +## Main definitions + +* `parallelComp (κ : Kernel α β) (η : Kernel γ δ) : Kernel (α × γ) (β × δ)`: parallel composition + of two s-finite kernels. We define a notation `κ ∥ₖ η = parallelComp κ η`. + `∫⁻ bd, g bd ∂(κ ∥ₖ η) ac = ∫⁻ b, ∫⁻ d, g (b, d) ∂η ac.2 ∂κ ac.1` + +## Main statements + +* `parallelComp_comp_copy`: `(κ ∥ₖ η) ∘ₖ (copy α) = κ ×ₖ η` +* `deterministic_comp_copy`: for a deterministic kernel, copying then applying the kernel to + the two copies is the same as first applying the kernel then copying. That is, if `κ` is + a deterministic kernel, `(κ ∥ₖ κ) ∘ₖ copy α = copy β ∘ₖ κ`. + +## Notations + +* `κ ∥ₖ η = ProbabilityTheory.Kernel.parallelComp κ η` + +## Implementation notes + +Our formalization of kernels is centered around the composition-product: the product and then the +parallel composition are defined as special cases of the composition-product. +We could have alternatively used the building blocks of kernels seen as a Markov category: +composition, parallel composition (or tensor product) and the deterministic kernels `id`, `copy`, +`swap` and `discard`. The product and composition-product could then be built from these. + +-/ + +open MeasureTheory + +open scoped ENNReal + +namespace ProbabilityTheory.Kernel + +variable {α β γ δ : Type*} {mα : MeasurableSpace α} {mβ : MeasurableSpace β} + {mγ : MeasurableSpace γ} {mδ : MeasurableSpace δ} + +section ParallelComp + +/-- Parallel product of two kernels. -/ +noncomputable +def parallelComp (κ : Kernel α β) (η : Kernel γ δ) : Kernel (α × γ) (β × δ) := + (prodMkRight γ κ) ×ₖ (prodMkLeft α η) + +@[inherit_doc] +scoped[ProbabilityTheory] infixl:100 " ∥ₖ " => ProbabilityTheory.Kernel.parallelComp + +lemma parallelComp_apply (κ : Kernel α β) [IsSFiniteKernel κ] + (η : Kernel γ δ) [IsSFiniteKernel η] (x : α × γ) : + (κ ∥ₖ η) x = (κ x.1).prod (η x.2) := by + rw [parallelComp, prod_apply, prodMkRight_apply, prodMkLeft_apply] + +lemma lintegral_parallelComp (κ : Kernel α β) [IsSFiniteKernel κ] + (η : Kernel γ δ) [IsSFiniteKernel η] + (ac : α × γ) {g : β × δ → ℝ≥0∞} (hg : Measurable g) : + ∫⁻ bd, g bd ∂(κ ∥ₖ η) ac = ∫⁻ b, ∫⁻ d, g (b, d) ∂η ac.2 ∂κ ac.1 := by + rw [parallelComp, lintegral_prod _ _ _ hg] + simp + +instance (κ : Kernel α β) (η : Kernel γ δ) : IsSFiniteKernel (κ ∥ₖ η) := by + rw [parallelComp]; infer_instance + +instance (κ : Kernel α β) [IsFiniteKernel κ] (η : Kernel γ δ) [IsFiniteKernel η] : + IsFiniteKernel (κ ∥ₖ η) := by + rw [parallelComp]; infer_instance + +instance (κ : Kernel α β) [IsMarkovKernel κ] (η : Kernel γ δ) [IsMarkovKernel η] : + IsMarkovKernel (κ ∥ₖ η) := by + rw [parallelComp]; infer_instance + +instance (κ : Kernel α β) [IsZeroOrMarkovKernel κ] (η : Kernel γ δ) [IsZeroOrMarkovKernel η] : + IsZeroOrMarkovKernel (κ ∥ₖ η) := by + rw [parallelComp]; infer_instance + +lemma parallelComp_comp_copy (κ : Kernel α β) [IsSFiniteKernel κ] + (η : Kernel α γ) [IsSFiniteKernel η] : + (κ ∥ₖ η) ∘ₖ (copy α) = κ ×ₖ η := by + ext a s hs + simp_rw [prod_apply, comp_apply, copy_apply, Measure.bind_apply hs (Kernel.measurable _)] + rw [lintegral_dirac'] + swap; · exact Kernel.measurable_coe _ hs + rw [parallelComp_apply] + +lemma swap_parallelComp {κ : Kernel α β} [IsSFiniteKernel κ] + {η : Kernel γ δ} [IsSFiniteKernel η] : + (swap β δ) ∘ₖ (κ ∥ₖ η) = (η ∥ₖ κ) ∘ₖ (swap α γ) := by + rw [parallelComp, swap_prod, parallelComp] + ext ac s hs + rw [comp_apply, swap_apply, Measure.bind_apply hs (Kernel.measurable _), + lintegral_dirac' _ (Kernel.measurable_coe _ hs), prod_apply, prod_apply, prodMkLeft_apply, + prodMkLeft_apply, prodMkRight_apply, prodMkRight_apply] + rfl + +/-- For a deterministic kernel, copying then applying the kernel to the two copies is the same +as first applying the kernel then copying. -/ +lemma deterministic_comp_copy {f : α → β} (hf : Measurable f) : + (Kernel.deterministic f hf ∥ₖ Kernel.deterministic f hf) ∘ₖ Kernel.copy α + = Kernel.copy β ∘ₖ Kernel.deterministic f hf := by + rw [Kernel.parallelComp_comp_copy, Kernel.deterministic_prod_deterministic, + Kernel.copy, Kernel.deterministic_comp_deterministic] + rfl + +end ParallelComp + +end ProbabilityTheory.Kernel diff --git a/Mathlib/Probability/Kernel/Disintegration/Basic.lean b/Mathlib/Probability/Kernel/Disintegration/Basic.lean index 22934beefaf08..8d443a75e791c 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Basic.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Yaël Dillies, Kin Yau James Wong. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yaël Dillies, Kin Yau James Wong, Rémy Degenne -/ -import Mathlib.Probability.Kernel.MeasureCompProd +import Mathlib.Probability.Kernel.Composition.MeasureCompProd /-! # Disintegration of measures and kernels diff --git a/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean index 4bdb5515cd2ee..a8558585a52da 100644 --- a/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/CDFToKernel.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémy Degenne -/ import Mathlib.MeasureTheory.Function.AEEqOfIntegral -import Mathlib.Probability.Kernel.Composition +import Mathlib.Probability.Kernel.Composition.Basic import Mathlib.Probability.Kernel.Disintegration.MeasurableStieltjes /-! diff --git a/Mathlib/Probability/Kernel/Disintegration/Density.lean b/Mathlib/Probability/Kernel/Disintegration/Density.lean index 94af1027b716b..316c64c2fce93 100644 --- a/Mathlib/Probability/Kernel/Disintegration/Density.lean +++ b/Mathlib/Probability/Kernel/Disintegration/Density.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Rémy Degenne. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémy Degenne -/ -import Mathlib.Probability.Kernel.Composition +import Mathlib.Probability.Kernel.Composition.Basic import Mathlib.Probability.Martingale.Convergence import Mathlib.Probability.Process.PartitionFiltration diff --git a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean index d89d6a2aefef8..9f1b75f64926a 100644 --- a/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean +++ b/Mathlib/Probability/Kernel/Disintegration/StandardBorel.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Rémy Degenne. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Rémy Degenne -/ -import Mathlib.Probability.Kernel.MeasureCompProd +import Mathlib.Probability.Kernel.Composition.MeasureCompProd import Mathlib.Probability.Kernel.Disintegration.Basic import Mathlib.Probability.Kernel.Disintegration.CondCDF import Mathlib.Probability.Kernel.Disintegration.Density diff --git a/Mathlib/Probability/Kernel/Invariance.lean b/Mathlib/Probability/Kernel/Invariance.lean index e9d40e85a0dd9..c58725ae3dd90 100644 --- a/Mathlib/Probability/Kernel/Invariance.lean +++ b/Mathlib/Probability/Kernel/Invariance.lean @@ -3,7 +3,7 @@ Copyright (c) 2023 Kexing Ying. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kexing Ying -/ -import Mathlib.Probability.Kernel.Composition +import Mathlib.Probability.Kernel.Composition.Basic /-! # Invariance of measures along a kernel diff --git a/Mathlib/Probability/Moments.lean b/Mathlib/Probability/Moments.lean index 5cd7261ecfd42..1178661e1715f 100644 --- a/Mathlib/Probability/Moments.lean +++ b/Mathlib/Probability/Moments.lean @@ -184,6 +184,9 @@ theorem mgf_neg : mgf (-X) μ t = mgf X μ (-t) := by simp_rw [mgf, Pi.neg_apply theorem cgf_neg : cgf (-X) μ t = cgf X μ (-t) := by simp_rw [cgf, mgf_neg] +theorem mgf_smul_left (α : ℝ) : mgf (α • X) μ t = mgf X μ (α * t) := by + simp_rw [mgf, Pi.smul_apply, smul_eq_mul, mul_comm α t, mul_assoc] + /-- This is a trivial application of `IndepFun.comp` but it will come up frequently. -/ theorem IndepFun.exp_mul {X Y : Ω → ℝ} (h_indep : IndepFun X Y μ) (s t : ℝ) : IndepFun (fun ω => exp (s * X ω)) (fun ω => exp (t * Y ω)) μ := by diff --git a/Mathlib/Probability/StrongLaw.lean b/Mathlib/Probability/StrongLaw.lean index 4740c2314e1fb..9094e67f68a42 100644 --- a/Mathlib/Probability/StrongLaw.lean +++ b/Mathlib/Probability/StrongLaw.lean @@ -436,7 +436,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : apply mul_le_mul_of_nonneg_right _ (variance_nonneg _ _) convert sum_div_nat_floor_pow_sq_le_div_sq N (Nat.cast_pos.2 hj) c_one using 2 · simp only [Nat.cast_lt] - · simp only [one_div] + · simp only [Y, S, u, C, one_div] _ = c ^ 5 * (c - 1)⁻¹ ^ 3 * ∑ j ∈ range (u (N - 1)), ((j : ℝ) ^ 2)⁻¹ * Var[Y j] := by simp_rw [mul_sum, div_eq_mul_inv, mul_assoc] _ ≤ c ^ 5 * (c - 1)⁻¹ ^ 3 * (2 * 𝔼[X 0]) := by @@ -475,7 +475,7 @@ theorem strong_law_aux1 {c : ℝ} (c_one : 1 < c) {ε : ℝ} (εpos : 0 < ε) : ENNReal.ofReal_lt_top filter_upwards [ae_eventually_not_mem I4.ne] with ω hω simp_rw [S, not_le, mul_comm, sum_apply] at hω - convert hω; simp only [sum_apply] + convert hω; simp only [Y, S, u, C, sum_apply] include hint hindep hident hnonneg in /- The truncation of `Xᵢ` up to `i` satisfies the strong law of large numbers @@ -634,8 +634,8 @@ theorem strong_law_ae_real {Ω : Type*} {m : MeasurableSpace Ω} {μ : Measure convert hωpos.sub hωneg using 2 · simp only [pos, neg, ← sub_div, ← sum_sub_distrib, max_zero_sub_max_neg_zero_eq_self, Function.comp_apply] - · simp only [← integral_sub hint.pos_part hint.neg_part, max_zero_sub_max_neg_zero_eq_self, - Function.comp_apply, mΩ] + · simp only [← integral_sub hint.pos_part hint.neg_part, + max_zero_sub_max_neg_zero_eq_self, Function.comp_apply, mΩ] end StrongLawAeReal @@ -684,7 +684,7 @@ lemma strong_law_ae_simpleFunc_comp (X : ℕ → Ω → E) (h' : Measurable (X 0 simp simp only [I, integral_smul_const] convert Tendsto.smul_const hω c using 1 - simp [Y, ← sum_smul, smul_smul] + simp [F, Y, ← sum_smul, smul_smul] · rintro φ ψ - hφ hψ filter_upwards [hφ, hψ] with ω hωφ hωψ convert hωφ.add hωψ using 1 diff --git a/Mathlib/RepresentationTheory/Basic.lean b/Mathlib/RepresentationTheory/Basic.lean index f17cfb213b7e5..7240eabf32ae6 100644 --- a/Mathlib/RepresentationTheory/Basic.lean +++ b/Mathlib/RepresentationTheory/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Antoine Labelle -/ import Mathlib.LinearAlgebra.Contraction +import Mathlib.Algebra.Group.Equiv.TypeTags /-! # Monoid representations diff --git a/Mathlib/RepresentationTheory/Character.lean b/Mathlib/RepresentationTheory/Character.lean index 5479f9417977f..cb98ce35c607a 100644 --- a/Mathlib/RepresentationTheory/Character.lean +++ b/Mathlib/RepresentationTheory/Character.lean @@ -116,8 +116,8 @@ theorem char_orthonormal (V W : FDRep k G) [Simple V] [Simple W] : rw [char_iso (FDRep.dualTensorIsoLinHom W.ρ V)] -- The average over the group of the character of a representation equals the dimension of the -- space of invariants. - rw [average_char_eq_finrank_invariants] - rw [show (of (linHom W.ρ V.ρ)).ρ = linHom W.ρ V.ρ from FDRep.of_ρ (linHom W.ρ V.ρ)] + rw [average_char_eq_finrank_invariants, ← FDRep.endMulEquiv_comp_ρ (of _), + FDRep.of_ρ (linHom W.ρ V.ρ)] -- The space of invariants of `Hom(W, V)` is the subspace of `G`-equivariant linear maps, -- `Hom_G(W, V)`. erw [(linHom.invariantsEquivFDRepHom W V).finrank_eq] -- Porting note: Changed `rw` to `erw` diff --git a/Mathlib/RepresentationTheory/FDRep.lean b/Mathlib/RepresentationTheory/FDRep.lean index 1f3f8535f0114..c3217c02d5c69 100644 --- a/Mathlib/RepresentationTheory/FDRep.lean +++ b/Mathlib/RepresentationTheory/FDRep.lean @@ -82,7 +82,18 @@ instance (V W : FDRep k G) : FiniteDimensional k (V ⟶ W) := /-- The monoid homomorphism corresponding to the action of `G` onto `V : FDRep k G`. -/ def ρ (V : FDRep k G) : G →* V →ₗ[k] V := - Action.ρ V + (ModuleCat.endMulEquiv _).toMonoidHom.comp (Action.ρ V) + +@[simp] +lemma endMulEquiv_symm_comp_ρ (V : FDRep k G) : + (MonoidHomClass.toMonoidHom (ModuleCat.endMulEquiv V.V.obj).symm).comp (ρ V) = Action.ρ V := rfl + +@[simp] +lemma endMulEquiv_comp_ρ (V : FDRep k G) : + (MonoidHomClass.toMonoidHom (ModuleCat.endMulEquiv V.V.obj)).comp (Action.ρ V) = ρ V := rfl + +@[simp] +lemma hom_action_ρ (V : FDRep k G) (g : G) : (Action.ρ V g).hom = ρ V g := rfl /-- The underlying `LinearEquiv` of an isomorphism of representations. -/ def isoToLinearEquiv {V W : FDRep k G} (i : V ≅ W) : V ≃ₗ[k] W := @@ -91,15 +102,16 @@ def isoToLinearEquiv {V W : FDRep k G} (i : V ≅ W) : V ≃ₗ[k] W := theorem Iso.conj_ρ {V W : FDRep k G} (i : V ≅ W) (g : G) : W.ρ g = (FDRep.isoToLinearEquiv i).conj (V.ρ g) := by -- Porting note: Changed `rw` to `erw` - erw [FDRep.isoToLinearEquiv, ← FGModuleCat.Iso.conj_eq_conj, Iso.conj_apply] - rw [Iso.eq_inv_comp ((Action.forget (FGModuleCat k) (MonCat.of G)).mapIso i)] + erw [FDRep.isoToLinearEquiv, ← hom_action_ρ V, ← FGModuleCat.Iso.conj_hom_eq_conj, Iso.conj_apply] + rw [← ModuleCat.hom_ofHom (W.ρ g), ← ModuleCat.hom_ext_iff, + Iso.eq_inv_comp ((Action.forget (FGModuleCat k) (MonCat.of G)).mapIso i)] exact (i.hom.comm g).symm /-- Lift an unbundled representation to `FDRep`. -/ @[simps ρ] def of {V : Type u} [AddCommGroup V] [Module k V] [FiniteDimensional k V] (ρ : Representation k G V) : FDRep k G := - ⟨FGModuleCat.of k V, ρ⟩ + ⟨FGModuleCat.of k V, ρ ≫ MonCat.ofHom (ModuleCat.endMulEquiv _).symm.toMonoidHom⟩ instance : HasForget₂ (FDRep k G) (Rep k G) where forget₂ := (forget₂ (FGModuleCat k) (ModuleCat k)).mapAction (MonCat.of G) @@ -179,11 +191,13 @@ noncomputable def dualTensorIsoLinHomAux : /-- When `V` and `W` are finite dimensional representations of a group `G`, the isomorphism `dualTensorHomEquiv k V W` of vector spaces induces an isomorphism of representations. -/ noncomputable def dualTensorIsoLinHom : FDRep.of ρV.dual ⊗ W ≅ FDRep.of (linHom ρV W.ρ) := by - refine Action.mkIso (dualTensorIsoLinHomAux ρV W) ?_ - convert dualTensorHom_comm ρV W.ρ + refine Action.mkIso (dualTensorIsoLinHomAux ρV W) (fun g => ?_) + ext : 1 + exact dualTensorHom_comm ρV W.ρ g @[simp] -theorem dualTensorIsoLinHom_hom_hom : (dualTensorIsoLinHom ρV W).hom.hom = dualTensorHom k V W := +theorem dualTensorIsoLinHom_hom_hom : + (dualTensorIsoLinHom ρV W).hom.hom = ModuleCat.ofHom (dualTensorHom k V W) := rfl end FDRep diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean index 2b6bd6ab54337..756771dc9da34 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Basic.lean @@ -121,9 +121,9 @@ morphisms in `Rep k G`) commutes with the differentials in the complex of inhomo and the homogeneous `linearYonedaObjResolution`. -/ @[nolint checkType] theorem d_eq : d n A = - (diagonalHomEquiv n A).toModuleIso.inv ≫ + ((diagonalHomEquiv n A).toModuleIso.inv ≫ (linearYonedaObjResolution A).d n (n + 1) ≫ - (diagonalHomEquiv (n + 1) A).toModuleIso.hom := by + (diagonalHomEquiv (n + 1) A).toModuleIso.hom).hom := by ext f g /- Porting note (https://github.com/leanprover-community/mathlib4/issues/11039): broken proof was simp only [ModuleCat.coe_comp, LinearEquiv.coe_coe, Function.comp_apply, @@ -146,7 +146,7 @@ and the homogeneous `linearYonedaObjResolution`. -/ -- https://github.com/leanprover-community/mathlib4/issues/5164 change d n A f g = diagonalHomEquiv (n + 1) A ((resolution k G).d (n + 1) n ≫ (diagonalHomEquiv n A).symm f) g - rw [diagonalHomEquiv_apply, Action.comp_hom, ModuleCat.comp_def, LinearMap.comp_apply, + rw [diagonalHomEquiv_apply, Action.comp_hom, ModuleCat.hom_comp, LinearMap.comp_apply, resolution.d_eq] erw [resolution.d_of (Fin.partialProd g)] simp only [map_sum, ← Finsupp.smul_single_one _ ((-1 : k) ^ _)] @@ -175,7 +175,7 @@ $$0 \to \mathrm{Fun}(G^0, A) \to \mathrm{Fun}(G^1, A) \to \mathrm{Fun}(G^2, A) \ which calculates the group cohomology of `A`. -/ noncomputable abbrev inhomogeneousCochains : CochainComplex (ModuleCat k) ℕ := CochainComplex.of (fun n => ModuleCat.of k ((Fin n → G) → A)) - (fun n => inhomogeneousCochains.d n A) fun n => by + (fun n => ModuleCat.ofHom (inhomogeneousCochains.d n A)) fun n => by /- Porting note (https://github.com/leanprover-community/mathlib4/issues/11039): broken proof was ext x y have := LinearMap.ext_iff.1 ((linearYonedaObjResolution A).d_comp_d n (n + 1) (n + 2)) @@ -184,20 +184,23 @@ noncomputable abbrev inhomogeneousCochains : CochainComplex (ModuleCat k) ℕ := LinearEquiv.toModuleIso_inv, LinearEquiv.coe_coe, LinearEquiv.symm_apply_apply, this, LinearMap.zero_apply, map_zero, Pi.zero_apply] -/ ext x - have := LinearMap.ext_iff.1 ((linearYonedaObjResolution A).d_comp_d n (n + 1) (n + 2)) - simp only [ModuleCat.comp_def, LinearMap.comp_apply] at this + have : ∀ x, _ = (0 : _ →ₗ[_] _) x := LinearMap.ext_iff.1 (ModuleCat.hom_ext_iff.mp + ((linearYonedaObjResolution A).d_comp_d n (n + 1) (n + 2))) + simp only [ModuleCat.hom_comp, LinearMap.comp_apply] at this dsimp only - simp only [d_eq, LinearEquiv.toModuleIso_inv, LinearEquiv.toModuleIso_hom, ModuleCat.coe_comp, - Function.comp_apply] + simp only [d_eq, LinearEquiv.toModuleIso_inv_hom, LinearEquiv.toModuleIso_hom_hom, + ModuleCat.hom_comp, LinearMap.comp_apply, LinearEquiv.coe_coe, ModuleCat.hom_zero] /- Porting note: I can see I need to rewrite `LinearEquiv.coe_coe` twice to at least reduce the need for `symm_apply_apply` to be an `erw`. However, even `erw` refuses to rewrite the second `coe_coe`... -/ erw [LinearEquiv.symm_apply_apply, this] - exact map_zero _ + simp only [LinearMap.zero_apply, ChainComplex.linearYonedaObj_X, linearYoneda_obj_obj_carrier, + map_zero, Pi.zero_apply, LinearMap.zero_apply] + rfl @[simp] theorem inhomogeneousCochains.d_def (n : ℕ) : - (inhomogeneousCochains A).d n (n + 1) = inhomogeneousCochains.d n A := + (inhomogeneousCochains A).d n (n + 1) = ModuleCat.ofHom (inhomogeneousCochains.d n A) := CochainComplex.of_d _ _ _ _ /-- Given a `k`-linear `G`-representation `A`, the complex of inhomogeneous cochains is isomorphic @@ -207,8 +210,15 @@ def inhomogeneousCochainsIso : inhomogeneousCochains A ≅ linearYonedaObjResolu (Rep.diagonalHomEquiv i A).toModuleIso.symm) ?_ rintro i j (h : i + 1 = j) subst h - simp only [CochainComplex.of_d, d_eq, Category.assoc, Iso.symm_hom, Iso.hom_inv_id, - Category.comp_id] + ext + simp only [ChainComplex.linearYonedaObj_X, linearYoneda_obj_obj_carrier, CochainComplex.of_x, + linearYoneda_obj_obj_isAddCommGroup, linearYoneda_obj_obj_isModule, Iso.symm_hom, + ChainComplex.linearYonedaObj_d, ModuleCat.hom_comp, linearYoneda_obj_map_hom, + Quiver.Hom.unop_op, LinearEquiv.toModuleIso_inv_hom, LinearMap.coe_comp, Function.comp_apply, + Linear.leftComp_apply, inhomogeneousCochains.d_def, d_eq, LinearEquiv.toModuleIso_hom_hom, + ModuleCat.ofHom_comp, Category.assoc, LinearEquiv.comp_coe, LinearEquiv.self_trans_symm, + LinearEquiv.refl_toLinearMap, LinearMap.id_comp, LinearEquiv.coe_coe] + rfl /-- 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. -/ diff --git a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean index 24d8d8f5bd37c..ff50887857737 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/LowDegree.lean @@ -142,7 +142,7 @@ square commutes: where the vertical arrows are `zeroCochainsLequiv` and `oneCochainsLequiv` respectively. -/ theorem dZero_comp_eq : dZero A ∘ₗ (zeroCochainsLequiv A) = - oneCochainsLequiv A ∘ₗ (inhomogeneousCochains A).d 0 1 := by + oneCochainsLequiv A ∘ₗ ((inhomogeneousCochains A).d 0 1).hom := by ext x y show A.ρ y (x default) - x default = _ + ({0} : Finset _).sum _ simp_rw [Fin.val_eq_zero, zero_add, pow_one, neg_smul, one_smul, @@ -163,7 +163,7 @@ square commutes: where the vertical arrows are `oneCochainsLequiv` and `twoCochainsLequiv` respectively. -/ theorem dOne_comp_eq : dOne A ∘ₗ oneCochainsLequiv A = - twoCochainsLequiv A ∘ₗ (inhomogeneousCochains A).d 1 2 := by + twoCochainsLequiv A ∘ₗ ((inhomogeneousCochains A).d 1 2).hom := by ext x y show A.ρ y.1 (x _) - x _ + x _ = _ + _ rw [Fin.sum_univ_two] @@ -185,7 +185,8 @@ square commutes: where the vertical arrows are `twoCochainsLequiv` and `threeCochainsLequiv` respectively. -/ theorem dTwo_comp_eq : - dTwo A ∘ₗ twoCochainsLequiv A = threeCochainsLequiv A ∘ₗ (inhomogeneousCochains A).d 2 3 := by + dTwo A ∘ₗ twoCochainsLequiv A = + threeCochainsLequiv A ∘ₗ ((inhomogeneousCochains A).d 2 3).hom := by ext x y show A.ρ y.1 (x _) - x _ + x _ - x _ = _ + _ dsimp @@ -201,12 +202,13 @@ theorem dOne_comp_dZero : dOne A ∘ₗ dZero A = 0 := by rfl theorem dTwo_comp_dOne : dTwo A ∘ₗ dOne A = 0 := by - show ModuleCat.asHom (dOne A) ≫ ModuleCat.asHom (dTwo A) = _ - have h1 : _ ≫ ModuleCat.asHom (dOne A) = _ ≫ _ := congr_arg ModuleCat.asHom (dOne_comp_eq A) - have h2 : _ ≫ ModuleCat.asHom (dTwo A) = _ ≫ _ := congr_arg ModuleCat.asHom (dTwo_comp_eq A) - simp only [← LinearEquiv.toModuleIso_hom] at h1 h2 - simp only [(Iso.eq_inv_comp _).2 h2, (Iso.eq_inv_comp _).2 h1, - Category.assoc, Iso.hom_inv_id_assoc, HomologicalComplex.d_comp_d_assoc, zero_comp, comp_zero] + show (ModuleCat.ofHom (dOne A) ≫ ModuleCat.ofHom (dTwo A)).hom = _ + have h1 := congr_arg ModuleCat.ofHom (dOne_comp_eq A) + have h2 := congr_arg ModuleCat.ofHom (dTwo_comp_eq A) + simp only [ModuleCat.ofHom_comp, ModuleCat.ofHom_comp, ← LinearEquiv.toModuleIso_hom_hom] at h1 h2 + simp only [(Iso.eq_inv_comp _).2 h2, (Iso.eq_inv_comp _).2 h1, ModuleCat.ofHom_hom, + ModuleCat.hom_ofHom, Category.assoc, Iso.hom_inv_id_assoc, HomologicalComplex.d_comp_d_assoc, + zero_comp, comp_zero, ModuleCat.hom_zero] end Differentials @@ -749,9 +751,9 @@ lemma shortComplexH0_exact : (shortComplexH0 A).Exact := by `(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.asHom (dZero A)) := + Arrow.mk (ModuleCat.ofHom (dZero A)) := Arrow.isoMk (zeroCochainsLequiv A).toModuleIso - (oneCochainsLequiv A).toModuleIso (dZero_comp_eq A) + (oneCochainsLequiv A).toModuleIso (ModuleCat.hom_ext (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. -/ @@ -761,7 +763,7 @@ def isoZeroCocycles : cocycles A 0 ≅ ModuleCat.of k A.ρ.invariants := (dZeroArrowIso A) lemma isoZeroCocycles_hom_comp_subtype : - (isoZeroCocycles A).hom ≫ A.ρ.invariants.subtype = + (isoZeroCocycles A).hom ≫ ModuleCat.ofHom A.ρ.invariants.subtype = iCocycles A 0 ≫ (zeroCochainsLequiv A).toModuleIso.hom := by dsimp [isoZeroCocycles] apply KernelFork.mapOfIsLimit_ι @@ -788,7 +790,9 @@ 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) + (twoCochainsLequiv A).toModuleIso + (ModuleCat.hom_ext (dZero_comp_eq A)) + (ModuleCat.hom_ext (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. -/ @@ -797,7 +801,7 @@ def isoOneCocycles : cocycles A 1 ≅ ModuleCat.of k (oneCocycles A) := cyclesMapIso (shortComplexH1Iso A) ≪≫ (shortComplexH1 A).moduleCatCyclesIso lemma isoOneCocycles_hom_comp_subtype : - (isoOneCocycles A).hom ≫ ModuleCat.asHom (oneCocycles A).subtype = + (isoOneCocycles A).hom ≫ ModuleCat.ofHom (oneCocycles A).subtype = iCocycles A 1 ≫ (oneCochainsLequiv A).toModuleIso.hom := by dsimp [isoOneCocycles] rw [Category.assoc, Category.assoc] @@ -807,9 +811,8 @@ lemma isoOneCocycles_hom_comp_subtype : lemma toCocycles_comp_isoOneCocycles_hom : toCocycles A 0 1 ≫ (isoOneCocycles A).hom = (zeroCochainsLequiv A).toModuleIso.hom ≫ - ModuleCat.asHom (shortComplexH1 A).moduleCatToCycles := by + 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. -/ @@ -836,7 +839,9 @@ isomorphic to the 2nd short complex associated to the complex of inhomogeneous c 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) + (threeCochainsLequiv A).toModuleIso + (ModuleCat.hom_ext (dOne_comp_eq A)) + (ModuleCat.hom_ext (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. -/ @@ -845,7 +850,7 @@ def isoTwoCocycles : cocycles A 2 ≅ ModuleCat.of k (twoCocycles A) := cyclesMapIso (shortComplexH2Iso A) ≪≫ (shortComplexH2 A).moduleCatCyclesIso lemma isoTwoCocycles_hom_comp_subtype : - (isoTwoCocycles A).hom ≫ ModuleCat.asHom (twoCocycles A).subtype = + (isoTwoCocycles A).hom ≫ ModuleCat.ofHom (twoCocycles A).subtype = iCocycles A 2 ≫ (twoCochainsLequiv A).toModuleIso.hom := by dsimp [isoTwoCocycles] rw [Category.assoc, Category.assoc] @@ -855,9 +860,8 @@ lemma isoTwoCocycles_hom_comp_subtype : lemma toCocycles_comp_isoTwoCocycles_hom : toCocycles A 1 2 ≫ (isoTwoCocycles A).hom = (oneCochainsLequiv A).toModuleIso.hom ≫ - ModuleCat.asHom (shortComplexH2 A).moduleCatToCycles := by + 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. -/ diff --git a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean index 564819a98563f..fedc31c3c9a40 100644 --- a/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean +++ b/Mathlib/RepresentationTheory/GroupCohomology/Resolution.lean @@ -320,11 +320,8 @@ theorem diagonalHomEquiv_symm_apply (f : (Fin n → G) → A) (x : Fin (n + 1) one_smul, Rep.of_ρ, Rep.Action_ρ_eq_ρ, Rep.trivial_def (x 0)⁻¹, Finsupp.llift_apply A k k] -/ simp only [LinearEquiv.trans_symm, LinearEquiv.symm_symm, LinearEquiv.trans_apply, leftRegularHomEquiv_symm_apply, Linear.homCongr_symm_apply, Iso.trans_hom, Iso.refl_inv, - Category.comp_id, Action.comp_hom, MonoidalClosed.linearHomEquivComm_symm_hom] - -- Porting note: This is a sure sign that coercions for morphisms in `ModuleCat` - -- are still not set up properly. - rw [ModuleCat.coe_comp] - simp only [ModuleCat.coe_comp, Function.comp_apply] + Category.comp_id, Action.comp_hom, MonoidalClosed.linearHomEquivComm_symm_hom, + ModuleCat.hom_comp, LinearMap.comp_apply] -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 erw [diagonalSucc_hom_single] -- The prototype linter that checks if `erw` could be replaced with `rw` would time out @@ -482,7 +479,9 @@ instance x_projective (G : Type u) [Group G] (n : ℕ) : /-- Simpler expression for the differential in the standard resolution of `k` as a `G`-representation. It sends `(g₀, ..., gₙ₊₁) ↦ ∑ (-1)ⁱ • (g₀, ..., ĝᵢ, ..., gₙ₊₁)`. -/ -theorem d_eq (n : ℕ) : ((groupCohomology.resolution k G).d (n + 1) n).hom = d k G (n + 1) := by +theorem d_eq (n : ℕ) : ((groupCohomology.resolution k G).d (n + 1) n).hom = + ModuleCat.ofHom (d k G (n + 1)) := by + ext : 1 refine Finsupp.lhom_ext' fun x => LinearMap.ext_ring ?_ dsimp [groupCohomology.resolution] /- Porting note (https://github.com/leanprover-community/mathlib4/issues/11039): broken proof was @@ -490,11 +489,12 @@ theorem d_eq (n : ℕ) : ((groupCohomology.resolution k G).d (n + 1) n).hom = d simp_rw [alternatingFaceMapComplex_obj_d, AlternatingFaceMapComplex.objD, SimplicialObject.δ, Functor.comp_map, ← Int.cast_smul_eq_zsmul k ((-1) ^ _ : ℤ), Int.cast_pow, Int.cast_neg, Int.cast_one, Action.sum_hom, Action.smul_hom, Rep.linearization_map_hom] - rw [LinearMap.coeFn_sum, Fintype.sum_apply] + rw [ModuleCat.hom_sum, LinearMap.coeFn_sum, Fintype.sum_apply] erw [d_of (k := k) x] /- Porting note: want to rewrite `LinearMap.smul_apply` but simp/simp_rw won't do it; I need erw, so using Finset.sum_congr to get rid of the binder -/ refine Finset.sum_congr rfl fun _ _ => ?_ + simp only [ModuleCat.hom_smul, SimplexCategory.len_mk] erw [LinearMap.smul_apply] rw [Finsupp.lmapDomain_apply, Finsupp.mapDomain_single, Finsupp.smul_single', mul_one] rfl @@ -533,8 +533,8 @@ def forget₂ToModuleCatHomotopyEquiv : /-- The hom of `k`-linear `G`-representations `k[G¹] → k` sending `∑ nᵢgᵢ ↦ ∑ nᵢ`. -/ def ε : Rep.ofMulAction k G (Fin 1 → G) ⟶ Rep.trivial k G k where - hom := Finsupp.linearCombination _ fun _ => (1 : k) - comm g := Finsupp.lhom_ext' fun _ => LinearMap.ext_ring (by + hom := ModuleCat.ofHom <| Finsupp.linearCombination _ fun _ => (1 : k) + comm g := ModuleCat.hom_ext <| Finsupp.lhom_ext' fun _ => LinearMap.ext_ring (by show Finsupp.linearCombination k (fun _ => (1 : k)) (Finsupp.mapDomain _ (Finsupp.single _ _)) = Finsupp.linearCombination k (fun _ => (1 : k)) (Finsupp.single _ _) @@ -551,7 +551,8 @@ theorem forget₂ToModuleCatHomotopyEquiv_f_0_eq : convert Category.id_comp (X := (forget₂ToModuleCat k G).X 0) _ · dsimp only [HomotopyEquiv.ofIso, compForgetAugmentedIso] simp only [Iso.symm_hom, eqToIso.inv, HomologicalComplex.eqToHom_f, eqToHom_refl] - trans (linearCombination _ fun _ => (1 : k)).comp ((ModuleCat.free k).map (terminal.from _)) + ext : 1 + trans (linearCombination _ fun _ => (1 : k)).comp ((ModuleCat.free k).map (terminal.from _)).hom · erw [Finsupp.lmapDomain_linearCombination (α := Fin 1 → G) (R := k) (α' := ⊤_ Type u) (v := fun _ => (1 : k)) (v' := fun _ => (1 : k)) (terminal.from @@ -563,21 +564,19 @@ theorem forget₂ToModuleCatHomotopyEquiv_f_0_eq : · ext x dsimp (config := { unfoldPartialApp := true }) [HomotopyEquiv.ofIso, Finsupp.LinearEquiv.finsuppUnique] - rw [linearCombination_single, one_smul, - @Unique.eq_default _ Types.terminalIso.toEquiv.unique x, - ChainComplex.single₀_map_f_zero, LinearMap.coe_mk, AddHom.coe_mk, Function.comp_apply, - Finsupp.equivFunOnFinite_apply, Finsupp.single_eq_same] + rw [@Unique.eq_default _ Types.terminalIso.toEquiv.unique x] + simp · exact @Subsingleton.elim _ (@Unique.instSubsingleton _ (Limits.uniqueToTerminal _)) _ _ theorem d_comp_ε : (groupCohomology.resolution k G).d 1 0 ≫ ε k G = 0 := by ext : 1 - refine LinearMap.ext fun x => ?_ + refine ModuleCat.hom_ext <| LinearMap.ext fun x => ?_ have : (forget₂ToModuleCat k G).d 1 0 ≫ (forget₂ (Rep k G) (ModuleCat.{u} k)).map (ε k G) = 0 := by rw [← forget₂ToModuleCatHomotopyEquiv_f_0_eq, ← (forget₂ToModuleCatHomotopyEquiv k G).1.2 1 0 rfl] exact comp_zero - exact LinearMap.ext_iff.1 this _ + exact LinearMap.ext_iff.1 (ModuleCat.hom_ext_iff.mp this) _ /-- The chain map from the standard resolution of `k` to `k[0]` given by `∑ nᵢgᵢ ↦ ∑ nᵢ` in degree zero. -/ diff --git a/Mathlib/RepresentationTheory/Invariants.lean b/Mathlib/RepresentationTheory/Invariants.lean index 898d8d3427513..acf708f7c06b9 100644 --- a/Mathlib/RepresentationTheory/Invariants.lean +++ b/Mathlib/RepresentationTheory/Invariants.lean @@ -121,19 +121,23 @@ variable {k : Type u} [CommRing k] {G : Grp.{u}} theorem mem_invariants_iff_comm {X Y : Rep k G} (f : X.V →ₗ[k] Y.V) (g : G) : (linHom X.ρ Y.ρ) g f = f ↔ f.comp (X.ρ g) = (Y.ρ g).comp f := by dsimp - erw [← ρAut_apply_inv] - rw [← LinearMap.comp_assoc, ← ModuleCat.comp_def, ← ModuleCat.comp_def, Iso.inv_comp_eq, - ρAut_apply_hom] + rw [← LinearMap.comp_assoc, ← ModuleCat.hom_ofHom (Y.ρ g), ← ModuleCat.hom_ofHom f, + ← ModuleCat.hom_comp, ← ModuleCat.hom_ofHom (X.ρ g⁻¹), ← ModuleCat.hom_comp, + Rep.ofHom_ρ, ← ρAut_apply_inv X g, Rep.ofHom_ρ, ← ρAut_apply_hom Y g, ← ModuleCat.hom_ext_iff, + Iso.inv_comp_eq, ρAut_apply_hom, ← ModuleCat.hom_ofHom (X.ρ g), + ← ModuleCat.hom_comp, ← ModuleCat.hom_ext_iff] exact comm /-- The invariants of the representation `linHom X.ρ Y.ρ` correspond to the representation homomorphisms from `X` to `Y`. -/ @[simps] def invariantsEquivRepHom (X Y : Rep k G) : (linHom X.ρ Y.ρ).invariants ≃ₗ[k] X ⟶ Y where - toFun f := ⟨f.val, fun g => (mem_invariants_iff_comm _ g).1 (f.property g)⟩ + toFun f := ⟨ModuleCat.ofHom f.val, fun g => + ModuleCat.hom_ext ((mem_invariants_iff_comm _ g).1 (f.property g))⟩ map_add' _ _ := rfl map_smul' _ _ := rfl - invFun f := ⟨f.hom, fun g => (mem_invariants_iff_comm _ g).2 (f.comm g)⟩ + invFun f := ⟨f.hom.hom, fun g => + (mem_invariants_iff_comm _ g).2 (ModuleCat.hom_ext_iff.mp (f.comm g))⟩ left_inv _ := by ext; rfl right_inv _ := by ext; rfl diff --git a/Mathlib/RepresentationTheory/Rep.lean b/Mathlib/RepresentationTheory/Rep.lean index 0a14328b88a96..342bac0e56cf4 100644 --- a/Mathlib/RepresentationTheory/Rep.lean +++ b/Mathlib/RepresentationTheory/Rep.lean @@ -61,11 +61,11 @@ instance (V : Rep k G) : Module k V := by -/ def ρ (V : Rep k G) : Representation k G V := -- Porting note: was `V.ρ` - Action.ρ V + (ModuleCat.endMulEquiv V.V).toMonoidHom.comp (Action.ρ V) /-- Lift an unbundled representation to `Rep`. -/ def of {V : Type u} [AddCommGroup V] [Module k V] (ρ : G →* V →ₗ[k] V) : Rep k G := - ⟨ModuleCat.of k V, ρ⟩ + ⟨ModuleCat.of k V, MonCat.ofHom ((ModuleCat.endMulEquiv _).symm.toMonoidHom.comp ρ) ⟩ @[simp] theorem coe_of {V : Type u} [AddCommGroup V] [Module k V] (ρ : G →* V →ₗ[k] V) : @@ -76,9 +76,16 @@ theorem coe_of {V : Type u} [AddCommGroup V] [Module k V] (ρ : G →* V →ₗ[ theorem of_ρ {V : Type u} [AddCommGroup V] [Module k V] (ρ : G →* V →ₗ[k] V) : (of ρ).ρ = ρ := rfl -theorem Action_ρ_eq_ρ {A : Rep k G} : Action.ρ A = A.ρ := +theorem Action_ρ_eq_ρ {A : Rep k G} : + Action.ρ A = (ModuleCat.endMulEquiv _).symm.toMonoidHom.comp A.ρ := rfl +@[simp] +lemma ρ_hom {X : Rep k G} (g : G) : (Action.ρ X g).hom = X.ρ g := rfl + +@[simp] +lemma ofHom_ρ {X : Rep k G} (g : G) : ModuleCat.ofHom (X.ρ g) = Action.ρ X g := rfl + /-- Allows us to apply lemmas about the underlying `ρ`, which would take an element `g : G` rather than `g : MonCat.of G` as an argument. -/ theorem of_ρ_apply {V : Type u} [AddCommGroup V] [Module k V] (ρ : Representation k G V) @@ -97,7 +104,7 @@ theorem ρ_self_inv_apply {G : Type u} [Group G] {A : Rep k G} (g : G) (x : A) : theorem hom_comm_apply {A B : Rep k G} (f : A ⟶ B) (g : G) (x : A) : f.hom (A.ρ g x) = B.ρ g (f.hom x) := - LinearMap.ext_iff.1 (f.comm g) x + LinearMap.ext_iff.1 (ModuleCat.hom_ext_iff.mp (f.comm g)) x variable (k G) @@ -172,7 +179,8 @@ theorem linearization_single (X : Action (Type u) (MonCat.of G)) (g : G) (x : X. variable {X Y : Action (Type u) (MonCat.of G)} (f : X ⟶ Y) @[simp] -theorem linearization_map_hom : ((linearization k G).map f).hom = Finsupp.lmapDomain k k f.hom := +theorem linearization_map_hom : ((linearization k G).map f).hom = + ModuleCat.ofHom (Finsupp.lmapDomain k k f.hom) := rfl theorem linearization_map_hom_single (x : X.V) (r : k) : @@ -183,16 +191,19 @@ open Functor.LaxMonoidal Functor.OplaxMonoidal Functor.Monoidal @[simp] theorem linearization_μ_hom (X Y : Action (Type u) (MonCat.of G)) : - (μ (linearization k G) X Y).hom = (finsuppTensorFinsupp' k X.V Y.V).toLinearMap := + (μ (linearization k G) X Y).hom = + ModuleCat.ofHom (finsuppTensorFinsupp' k X.V Y.V).toLinearMap := rfl @[simp] theorem linearization_δ_hom (X Y : Action (Type u) (MonCat.of G)) : - (δ (linearization k G) X Y).hom = (finsuppTensorFinsupp' k X.V Y.V).symm.toLinearMap := + (δ (linearization k G) X Y).hom = + ModuleCat.ofHom (finsuppTensorFinsupp' k X.V Y.V).symm.toLinearMap := rfl @[simp] -theorem linearization_ε_hom : (ε (linearization k G)).hom = Finsupp.lsingle PUnit.unit := +theorem linearization_ε_hom : (ε (linearization k G)).hom = + ModuleCat.ofHom (Finsupp.lsingle PUnit.unit) := rfl theorem linearization_η_hom_apply (r : k) : @@ -206,7 +217,7 @@ on `k[X]`. -/ @[simps!] noncomputable def linearizationTrivialIso (X : Type u) : (linearization k G).obj (Action.mk X 1) ≅ trivial k G (X →₀ k) := - Action.mkIso (Iso.refl _) fun _ => Finsupp.lhom_ext' fun _ => LinearMap.ext + Action.mkIso (Iso.refl _) fun _ => ModuleCat.hom_ext <| Finsupp.lhom_ext' fun _ => LinearMap.ext fun _ => linearization_single .. /-- Given a `G`-action on `H`, this is `k[H]` bundled with the natural representation @@ -269,14 +280,15 @@ variable {k G} `g ↦ A.ρ(g)(x).` -/ @[simps] noncomputable def leftRegularHom (A : Rep k G) (x : A) : Rep.ofMulAction k G G ⟶ A where - hom := Finsupp.lift _ _ _ fun g => A.ρ g x + hom := ModuleCat.ofHom <| Finsupp.lift _ _ _ fun g => A.ρ g x comm g := by + ext : 1 refine Finsupp.lhom_ext' fun y => LinearMap.ext_ring ?_ /- Porting note: rest of broken proof was simpa only [LinearMap.comp_apply, ModuleCat.comp_def, Finsupp.lsingle_apply, Finsupp.lift_apply, Action_ρ_eq_ρ, of_ρ_apply, Representation.ofMulAction_single, Finsupp.sum_single_index, zero_smul, one_smul, smul_eq_mul, A.ρ.map_mul] -/ - simp only [LinearMap.comp_apply, ModuleCat.comp_def, Finsupp.lsingle_apply] + simp only [LinearMap.comp_apply, ModuleCat.hom_comp, Finsupp.lsingle_apply] erw [Finsupp.lift_apply, Finsupp.lift_apply, Representation.ofMulAction_single (G := G)] simp only [Finsupp.sum_single_index, zero_smul, one_smul, smul_eq_mul, A.ρ.map_mul, of_ρ] rfl @@ -284,7 +296,7 @@ noncomputable def leftRegularHom (A : Rep k G) (x : A) : Rep.ofMulAction k G G theorem leftRegularHom_apply {A : Rep k G} (x : A) : (leftRegularHom A x).hom (Finsupp.single 1 1) = x := by -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [leftRegularHom_hom, Finsupp.lift_apply, Finsupp.sum_single_index, one_smul, + erw [leftRegularHom_hom_hom, Finsupp.lift_apply, Finsupp.sum_single_index, one_smul, A.ρ.map_one, LinearMap.one_apply] rw [zero_smul] @@ -297,14 +309,14 @@ noncomputable def leftRegularHomEquiv (A : Rep k G) : (Rep.ofMulAction k G G ⟶ map_smul' _ _ := rfl invFun x := leftRegularHom A x left_inv f := by - refine Action.Hom.ext (Finsupp.lhom_ext' fun x : G => LinearMap.ext_ring ?_) + refine Action.Hom.ext (ModuleCat.hom_ext (Finsupp.lhom_ext' fun x : G => LinearMap.ext_ring ?_)) have : f.hom ((ofMulAction k G G).ρ x (Finsupp.single (1 : G) (1 : k))) = A.ρ x (f.hom (Finsupp.single (1 : G) (1 : k))) := - LinearMap.ext_iff.1 (f.comm x) (Finsupp.single 1 1) - simp only [leftRegularHom_hom, LinearMap.comp_apply, Finsupp.lsingle_apply, Finsupp.lift_apply, - ← this, coe_of, of_ρ, Representation.ofMulAction_single x (1 : G) (1 : k), smul_eq_mul, - mul_one, zero_smul, Finsupp.sum_single_index, one_smul] + LinearMap.ext_iff.1 (ModuleCat.hom_ext_iff.mp (f.comm x)) (Finsupp.single 1 1) + simp only [leftRegularHom_hom_hom, LinearMap.comp_apply, Finsupp.lsingle_apply, + Finsupp.lift_apply, ← this, coe_of, of_ρ, Representation.ofMulAction_single x (1 : G) (1 : k), + smul_eq_mul, mul_one, zero_smul, Finsupp.sum_single_index, one_smul] -- Mismatched `Zero k` instances rfl right_inv x := leftRegularHom_apply x @@ -312,7 +324,7 @@ noncomputable def leftRegularHomEquiv (A : Rep k G) : (Rep.ofMulAction k G G ⟶ theorem leftRegularHomEquiv_symm_single {A : Rep k G} (x : A) (g : G) : ((leftRegularHomEquiv A).symm x).hom (Finsupp.single g 1) = A.ρ g x := by -- This used to be `rw`, but we need `erw` after https://github.com/leanprover/lean4/pull/2644 - erw [leftRegularHomEquiv_symm_apply, leftRegularHom_hom, Finsupp.lift_apply, + erw [leftRegularHomEquiv_symm_apply, leftRegularHom_hom_hom, Finsupp.lift_apply, Finsupp.sum_single_index, one_smul] rw [zero_smul] @@ -332,8 +344,8 @@ variable [Group G] (A B C : Rep k G) protected def ihom (A : Rep k G) : Rep k G ⥤ Rep k G where obj B := Rep.of (Representation.linHom A.ρ B.ρ) map := fun {X} {Y} f => - { hom := ModuleCat.asHom (LinearMap.llcomp k _ _ _ f.hom) - comm := fun g => LinearMap.ext fun x => LinearMap.ext fun y => by + { hom := ModuleCat.ofHom (LinearMap.llcomp k _ _ _ f.hom.hom) + comm := fun g => ModuleCat.hom_ext <| LinearMap.ext fun x => LinearMap.ext fun y => by show f.hom (X.ρ g _) = _ simp only [hom_comm_apply]; rfl } map_id := fun _ => by ext; rfl @@ -348,32 +360,33 @@ protected def ihom (A : Rep k G) : Rep k G ⥤ Rep k G where `k`-linear map underlying `f`, giving a map `A →ₗ[k] B →ₗ[k] C`, then flipping the arguments. -/ def homEquiv (A B C : Rep k G) : (A ⊗ B ⟶ C) ≃ (B ⟶ (Rep.ihom A).obj C) where toFun f := - { hom := (TensorProduct.curry f.hom).flip + { hom := ModuleCat.ofHom <| (TensorProduct.curry f.hom.hom).flip comm := fun g => by - refine LinearMap.ext fun x => LinearMap.ext fun y => ?_ + ext x : 2 + refine LinearMap.ext fun y => ?_ change f.hom (_ ⊗ₜ[k] _) = C.ρ g (f.hom (_ ⊗ₜ[k] _)) rw [← hom_comm_apply] change _ = f.hom ((A.ρ g * A.ρ g⁻¹) y ⊗ₜ[k] _) simp only [← map_mul, mul_inv_cancel, map_one] rfl } invFun f := - { hom := TensorProduct.uncurry k _ _ _ f.hom.flip - comm := fun g => TensorProduct.ext' fun x y => by -/- Porting note: rest of broken proof was + { hom := ModuleCat.ofHom <| TensorProduct.uncurry k _ _ _ f.hom.hom.flip + comm := fun g => ModuleCat.hom_ext <| TensorProduct.ext' fun x y => by + /- Porting note: rest of broken proof was dsimp only [MonoidalCategory.tensorLeft_obj, ModuleCat.comp_def, LinearMap.comp_apply, tensor_ρ, ModuleCat.MonoidalCategory.hom_apply, TensorProduct.map_tmul] simp only [TensorProduct.uncurry_apply f.hom.flip, LinearMap.flip_apply, Action_ρ_eq_ρ, hom_comm_apply f g y, Rep.ihom_obj_ρ_apply, LinearMap.comp_apply, ρ_inv_self_apply] -/ - change TensorProduct.uncurry k _ _ _ f.hom.flip (A.ρ g x ⊗ₜ[k] B.ρ g y) = - C.ρ g (TensorProduct.uncurry k _ _ _ f.hom.flip (x ⊗ₜ[k] y)) + change TensorProduct.uncurry k _ _ _ f.hom.hom.flip (A.ρ g x ⊗ₜ[k] B.ρ g y) = + C.ρ g (TensorProduct.uncurry k _ _ _ f.hom.hom.flip (x ⊗ₜ[k] y)) -- The next 3 tactics used to be `rw` before https://github.com/leanprover/lean4/pull/2644 erw [TensorProduct.uncurry_apply, LinearMap.flip_apply, hom_comm_apply, Rep.ihom_obj_ρ_apply, LinearMap.comp_apply, LinearMap.comp_apply] --, ρ_inv_self_apply (A := C)] dsimp rw [ρ_inv_self_apply] - rfl} - left_inv _ := Action.Hom.ext (TensorProduct.ext' fun _ _ => rfl) + rfl } + left_inv _ := Action.Hom.ext (ModuleCat.hom_ext (TensorProduct.ext' fun _ _ => rfl)) right_inv f := by ext; rfl variable {A B C} @@ -381,12 +394,13 @@ variable {A B C} /-- Porting note: if we generate this with `@[simps]` the linter complains some types in the LHS simplify. -/ theorem homEquiv_apply_hom (f : A ⊗ B ⟶ C) : - (homEquiv A B C f).hom = (TensorProduct.curry f.hom).flip := rfl + (homEquiv A B C f).hom = ModuleCat.ofHom (TensorProduct.curry f.hom.hom).flip := rfl /-- Porting note: if we generate this with `@[simps]` the linter complains some types in the LHS simplify. -/ theorem homEquiv_symm_apply_hom (f : B ⟶ (Rep.ihom A).obj C) : - ((homEquiv A B C).symm f).hom = TensorProduct.uncurry k A B C f.hom.flip := rfl + ((homEquiv A B C).symm f).hom = + ModuleCat.ofHom (TensorProduct.uncurry k A B C f.hom.hom.flip) := rfl instance : MonoidalClosed (Rep k G) where closed A := @@ -394,9 +408,9 @@ instance : MonoidalClosed (Rep k G) where adj := Adjunction.mkOfHomEquiv ( { homEquiv := Rep.homEquiv A homEquiv_naturality_left_symm := fun _ _ => Action.Hom.ext - (TensorProduct.ext' fun _ _ => rfl) - homEquiv_naturality_right := fun _ _ => Action.Hom.ext (LinearMap.ext - fun _ => LinearMap.ext fun _ => rfl) })} + (ModuleCat.hom_ext (TensorProduct.ext' fun _ _ => rfl)) + homEquiv_naturality_right := fun _ _ => Action.Hom.ext (ModuleCat.hom_ext (LinearMap.ext + fun _ => LinearMap.ext fun _ => rfl)) })} @[simp] theorem ihom_obj_ρ_def (A B : Rep k G) : ((ihom A).obj B).ρ = ((Rep.ihom A).obj B).ρ := @@ -408,13 +422,13 @@ theorem homEquiv_def (A B C : Rep k G) : (ihom.adjunction A).homEquiv B C = Rep. @[simp] theorem ihom_ev_app_hom (A B : Rep k G) : - Action.Hom.hom ((ihom.ev A).app B) - = TensorProduct.uncurry k A (A →ₗ[k] B) B LinearMap.id.flip := by + Action.Hom.hom ((ihom.ev A).app B) = ModuleCat.ofHom + (TensorProduct.uncurry k A (A →ₗ[k] B) B LinearMap.id.flip) := by ext; rfl @[simp] theorem ihom_coev_app_hom (A B : Rep k G) : - Action.Hom.hom ((ihom.coev A).app B) = (TensorProduct.mk k _ _).flip := - LinearMap.ext fun _ => LinearMap.ext fun _ => rfl + Action.Hom.hom ((ihom.coev A).app B) = ModuleCat.ofHom (TensorProduct.mk k _ _).flip := + ModuleCat.hom_ext <| LinearMap.ext fun _ => LinearMap.ext fun _ => rfl variable (A B C) @@ -435,25 +449,27 @@ variable {A B C} -- `simpNF` times out @[simp, nolint simpNF] theorem MonoidalClosed.linearHomEquiv_hom (f : A ⊗ B ⟶ C) : - (MonoidalClosed.linearHomEquiv A B C f).hom = (TensorProduct.curry f.hom).flip := + (MonoidalClosed.linearHomEquiv A B C f).hom = + ModuleCat.ofHom (TensorProduct.curry f.hom.hom).flip := rfl -- `simpNF` times out @[simp, nolint simpNF] theorem MonoidalClosed.linearHomEquivComm_hom (f : A ⊗ B ⟶ C) : - (MonoidalClosed.linearHomEquivComm A B C f).hom = TensorProduct.curry f.hom := + (MonoidalClosed.linearHomEquivComm A B C f).hom = + ModuleCat.ofHom (TensorProduct.curry f.hom.hom) := rfl theorem MonoidalClosed.linearHomEquiv_symm_hom (f : B ⟶ A ⟶[Rep k G] C) : ((MonoidalClosed.linearHomEquiv A B C).symm f).hom = - TensorProduct.uncurry k A B C f.hom.flip := by + ModuleCat.ofHom (TensorProduct.uncurry k A B C f.hom.hom.flip) := by simp [linearHomEquiv] rfl theorem MonoidalClosed.linearHomEquivComm_symm_hom (f : A ⟶ B ⟶[Rep k G] C) : - ((MonoidalClosed.linearHomEquivComm A B C).symm f).hom - = TensorProduct.uncurry k A B C f.hom := - TensorProduct.ext' fun _ _ => rfl + ((MonoidalClosed.linearHomEquivComm A B C).symm f).hom = + ModuleCat.ofHom (TensorProduct.uncurry k A B C f.hom.hom) := + ModuleCat.hom_ext <| TensorProduct.ext' fun _ _ => rfl end MonoidalClosed @@ -512,8 +528,10 @@ theorem to_Module_monoidAlgebra_map_aux {k G : Type*} [CommRing k] [Monoid G] (V /-- Auxiliary definition for `toModuleMonoidAlgebra`. -/ def toModuleMonoidAlgebraMap {V W : Rep k G} (f : V ⟶ W) : ModuleCat.of (MonoidAlgebra k G) V.ρ.asModule ⟶ ModuleCat.of (MonoidAlgebra k G) W.ρ.asModule := - { f.hom with - map_smul' := fun r x => to_Module_monoidAlgebra_map_aux V.V W.V V.ρ W.ρ f.hom f.comm r x } + ModuleCat.ofHom + { f.hom.hom with + map_smul' := fun r x => to_Module_monoidAlgebra_map_aux V.V W.V V.ρ W.ρ f.hom.hom + (fun g => ModuleCat.hom_ext_iff.mp (f.comm g)) r x } /-- Functorially convert a representation of `G` into a module over `MonoidAlgebra k G`. -/ def toModuleMonoidAlgebra : Rep k G ⥤ ModuleCat.{u} (MonoidAlgebra k G) where @@ -524,8 +542,10 @@ def toModuleMonoidAlgebra : Rep k G ⥤ ModuleCat.{u} (MonoidAlgebra k G) where def ofModuleMonoidAlgebra : ModuleCat.{u} (MonoidAlgebra k G) ⥤ Rep k G where obj M := Rep.of (Representation.ofModule M) map f := - { hom := { f with map_smul' := fun r x => f.map_smul (algebraMap k _ r) x } - comm := fun g => by ext; apply f.map_smul } + { hom := ModuleCat.ofHom + { f.hom with + map_smul' := fun r x => f.hom.map_smul (algebraMap k _ r) x } + comm := fun g => by ext; apply f.hom.map_smul } theorem ofModuleMonoidAlgebra_obj_coe (M : ModuleCat.{u} (MonoidAlgebra k G)) : (ofModuleMonoidAlgebra.obj M : Type u) = RestrictScalars k (MonoidAlgebra k G) M := @@ -551,7 +571,7 @@ def unitIsoAddEquiv {V : Rep k G} : V ≃+ (toModuleMonoidAlgebra ⋙ ofModuleMo /-- Auxiliary definition for `equivalenceModuleMonoidAlgebra`. -/ def counitIso (M : ModuleCat.{u} (MonoidAlgebra k G)) : (ofModuleMonoidAlgebra ⋙ toModuleMonoidAlgebra).obj M ≅ M := - LinearEquiv.toModuleIso' + LinearEquiv.toModuleIso { counitIsoAddEquiv with map_smul' := fun r x => by set_option tactic.skipAssignedInstances false in @@ -566,16 +586,13 @@ theorem unit_iso_comm (V : Rep k G) (g : G) (x : V) : unitIsoAddEquiv ((V.ρ g).toFun x) = ((ofModuleMonoidAlgebra.obj (toModuleMonoidAlgebra.obj V)).ρ g).toFun (unitIsoAddEquiv x) := by dsimp [unitIsoAddEquiv, ofModuleMonoidAlgebra, toModuleMonoidAlgebra] -/- Porting note: rest of broken proof was simp only [AddEquiv.apply_eq_iff_eq, AddEquiv.apply_symm_apply, - Representation.asModuleEquiv_symm_map_rho, Representation.ofModule_asModule_act] -/ - rw [Representation.asModuleEquiv_symm_map_rho] - rfl + Representation.asModuleEquiv_symm_map_rho, Representation.ofModule_asModule_act] /-- Auxiliary definition for `equivalenceModuleMonoidAlgebra`. -/ def unitIso (V : Rep k G) : V ≅ (toModuleMonoidAlgebra ⋙ ofModuleMonoidAlgebra).obj V := Action.mkIso - (LinearEquiv.toModuleIso' + (LinearEquiv.toModuleIso { unitIsoAddEquiv with map_smul' := fun r x => by dsimp [unitIsoAddEquiv] diff --git a/Mathlib/RingTheory/AdicCompletion/Algebra.lean b/Mathlib/RingTheory/AdicCompletion/Algebra.lean index 6f7c6168e2c6c..9c8babe6957b6 100644 --- a/Mathlib/RingTheory/AdicCompletion/Algebra.lean +++ b/Mathlib/RingTheory/AdicCompletion/Algebra.lean @@ -25,7 +25,7 @@ suppress_compilation open Submodule -variable {R : Type*} [CommRing R] (I : Ideal R) +variable {R S : Type*} [CommRing R] [CommRing S] (I : Ideal R) variable {M : Type*} [AddCommGroup M] [Module R M] namespace AdicCompletion @@ -87,8 +87,10 @@ instance : CommRing (AdicCompletion I R) := (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ ↦ rfl) -instance : Algebra R (AdicCompletion I R) where - toFun r := ⟨algebraMap R (∀ n, R ⧸ (I ^ n • ⊤ : Ideal R)) r, by simp⟩ +instance [Algebra S R] : Algebra S (AdicCompletion I R) where + toFun r := ⟨algebraMap S (∀ n, R ⧸ (I ^ n • ⊤ : Ideal R)) r, by + simp [-Ideal.Quotient.mk_algebraMap, + IsScalarTower.algebraMap_apply S R (R ⧸ (I ^ _ • ⊤ : Ideal R))]⟩ map_one' := Subtype.ext <| map_one _ map_mul' x y := Subtype.ext <| map_mul _ x y map_zero' := Subtype.ext <| map_zero _ @@ -252,23 +254,15 @@ instance module : Module (AdicCompletion I R) (AdicCompletion I M) where mul_smul r s x := by ext n simp only [smul_eval, val_mul, mul_smul] - smul_zero r := by - ext n - rw [smul_eval, val_zero, smul_zero] - smul_add r x y := by - ext n - simp only [smul_eval, val_add, smul_add] - add_smul r s x := by - ext n - simp only [coe_eval, smul_eval, map_add, add_smul, val_add] - zero_smul x := by - ext n - simp only [smul_eval, _root_.map_zero, zero_smul, val_zero] + smul_zero r := by ext n; simp + smul_add r x y := by ext n; simp + add_smul r s x := by ext n; simp [val_smul, add_smul] + zero_smul x := by ext n; simp instance : IsScalarTower R (AdicCompletion I R) (AdicCompletion I M) where smul_assoc r s x := by ext n - rw [smul_eval, val_smul, val_smul, smul_eval, smul_assoc] + rw [smul_eval, val_smul_apply, val_smul_apply, smul_eval, smul_assoc] /-- A priori `AdicCompletion I R` has two `AdicCompletion I R`-module instances. Both agree definitionally. -/ diff --git a/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean b/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean index 1c4dfed5cf15a..7327b43e29424 100644 --- a/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean +++ b/Mathlib/RingTheory/AdicCompletion/AsTensorProduct.lean @@ -8,7 +8,7 @@ import Mathlib.CategoryTheory.Abelian.DiagramLemmas.Four import Mathlib.LinearAlgebra.TensorProduct.Pi import Mathlib.LinearAlgebra.TensorProduct.RightExactness import Mathlib.RingTheory.AdicCompletion.Exactness -import Mathlib.RingTheory.Flat.Algebra +import Mathlib.RingTheory.Flat.Basic /-! @@ -101,7 +101,7 @@ private lemma piEquivOfFintype_comp_ofTensorProduct_eq : ext i j k suffices h : (if j = i then 1 else 0) = (if j = i then 1 else 0 : AdicCompletion I R).val k by simpa [Pi.single_apply, -smul_eq_mul, -Algebra.id.smul_eq_mul] - split <;> simp only [smul_eq_mul, val_zero, val_one] + split <;> simp private lemma ofTensorProduct_eq : ofTensorProduct I (ι → R) = (piEquivOfFintype I (ι := ι) (fun _ : ι ↦ R)).symm.toLinearMap ∘ₗ @@ -241,25 +241,25 @@ private instance : AddCommGroup (AdicCompletion I R ⊗[R] (LinearMap.ker f)) := private def firstRow : ComposableArrows (ModuleCat (AdicCompletion I R)) 4 := ComposableArrows.mk₄ - (ModuleCat.asHom <| lTensorKerIncl I M f) - (ModuleCat.asHom <| lTensorf I M f) - (ModuleCat.asHom (0 : AdicCompletion I R ⊗[R] M →ₗ[AdicCompletion I R] PUnit)) - (ModuleCat.asHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) + (ModuleCat.ofHom <| lTensorKerIncl I M f) + (ModuleCat.ofHom <| lTensorf I M f) + (ModuleCat.ofHom (0 : AdicCompletion I R ⊗[R] M →ₗ[AdicCompletion I R] PUnit)) + (ModuleCat.ofHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) private def secondRow : ComposableArrows (ModuleCat (AdicCompletion I R)) 4 := ComposableArrows.mk₄ - (ModuleCat.asHom (map I <| (LinearMap.ker f).subtype)) - (ModuleCat.asHom (map I f)) - (ModuleCat.asHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) - (ModuleCat.asHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) + (ModuleCat.ofHom (map I <| (LinearMap.ker f).subtype)) + (ModuleCat.ofHom (map I f)) + (ModuleCat.ofHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) + (ModuleCat.ofHom (0 : _ →ₗ[AdicCompletion I R] PUnit)) include hf private lemma firstRow_exact : (firstRow I M f).Exact where zero k _ := match k with - | 0 => (tens_exact I M f hf).linearMap_comp_eq_zero - | 1 => LinearMap.zero_comp _ - | 2 => LinearMap.zero_comp 0 + | 0 => ModuleCat.hom_ext (tens_exact I M f hf).linearMap_comp_eq_zero + | 1 => ModuleCat.hom_ext (LinearMap.zero_comp _) + | 2 => ModuleCat.hom_ext (LinearMap.zero_comp 0) exact k _ := by rw [ShortComplex.moduleCat_exact_iff] match k with @@ -269,9 +269,9 @@ private lemma firstRow_exact : (firstRow I M f).Exact where private lemma secondRow_exact [Fintype ι] [IsNoetherianRing R] : (secondRow I M f).Exact where zero k _ := match k with - | 0 => (adic_exact I M f hf).linearMap_comp_eq_zero - | 1 => LinearMap.zero_comp (map I f) - | 2 => LinearMap.zero_comp 0 + | 0 => ModuleCat.hom_ext (adic_exact I M f hf).linearMap_comp_eq_zero + | 1 => ModuleCat.hom_ext (LinearMap.zero_comp (map I f)) + | 2 => ModuleCat.hom_ext (LinearMap.zero_comp 0) exact k _ := by rw [ShortComplex.moduleCat_exact_iff] match k with @@ -282,25 +282,25 @@ private lemma secondRow_exact [Fintype ι] [IsNoetherianRing R] : (secondRow I M /- The compatible vertical maps between the first and the second row. -/ private def firstRowToSecondRow : firstRow I M f ⟶ secondRow I M f := ComposableArrows.homMk₄ - (ModuleCat.asHom (ofTensorProduct I (LinearMap.ker f))) - (ModuleCat.asHom (ofTensorProduct I (ι → R))) - (ModuleCat.asHom (ofTensorProduct I M)) - (ModuleCat.asHom 0) - (ModuleCat.asHom 0) - (ofTensorProduct_naturality I <| (LinearMap.ker f).subtype).symm - (ofTensorProduct_naturality I f).symm + (ModuleCat.ofHom (ofTensorProduct I (LinearMap.ker f))) + (ModuleCat.ofHom (ofTensorProduct I (ι → R))) + (ModuleCat.ofHom (ofTensorProduct I M)) + (ModuleCat.ofHom 0) + (ModuleCat.ofHom 0) + (ModuleCat.hom_ext (ofTensorProduct_naturality I <| (LinearMap.ker f).subtype).symm) + (ModuleCat.hom_ext (ofTensorProduct_naturality I f).symm) rfl rfl private lemma ofTensorProduct_iso [Fintype ι] [IsNoetherianRing R] : - IsIso (ModuleCat.asHom (ofTensorProduct I M)) := by + IsIso (ModuleCat.ofHom (ofTensorProduct I M)) := by refine Abelian.isIso_of_epi_of_isIso_of_isIso_of_mono (firstRow_exact I M f hf) (secondRow_exact I M f hf) (firstRowToSecondRow I M f) ?_ ?_ ?_ ?_ · apply ConcreteCategory.epi_of_surjective exact ofTensorProduct_surjective_of_finite I (LinearMap.ker f) · apply (ConcreteCategory.isIso_iff_bijective _).mpr exact ofTensorProduct_bijective_of_pi_of_fintype I ι - · show IsIso (ModuleCat.asHom 0) + · show IsIso (ModuleCat.ofHom 0) apply Limits.isIso_of_isTerminal <;> exact Limits.IsZero.isTerminal (ModuleCat.isZero_of_subsingleton _) · apply ConcreteCategory.mono_of_injective @@ -310,9 +310,9 @@ private lemma ofTensorProduct_iso [Fintype ι] [IsNoetherianRing R] : private lemma ofTensorProduct_bijective_of_map_from_fin [Fintype ι] [IsNoetherianRing R] : Function.Bijective (ofTensorProduct I M) := by - have : IsIso (ModuleCat.asHom (ofTensorProduct I M)) := + have : IsIso (ModuleCat.ofHom (ofTensorProduct I M)) := ofTensorProduct_iso I M f hf - exact ConcreteCategory.bijective_of_isIso (ModuleCat.asHom (ofTensorProduct I M)) + exact ConcreteCategory.bijective_of_isIso (ModuleCat.ofHom (ofTensorProduct I M)) end @@ -375,8 +375,8 @@ lemma tensor_map_id_left_injective_of_injective (hf : Function.Injective f) : end /-- Adic completion of a Noetherian ring `R` is flat over `R`. -/ -instance flat_of_isNoetherian [IsNoetherianRing R] : Algebra.Flat R (AdicCompletion I R) where - out := (Module.Flat.iff_lTensor_injective' R (AdicCompletion I R)).mpr <| fun J ↦ +instance flat_of_isNoetherian [IsNoetherianRing R] : Module.Flat R (AdicCompletion I R) := + (Module.Flat.iff_lTensor_injective' R (AdicCompletion I R)).mpr fun J ↦ tensor_map_id_left_injective_of_injective I (Submodule.injective_subtype J) end Noetherian diff --git a/Mathlib/RingTheory/AdicCompletion/Basic.lean b/Mathlib/RingTheory/AdicCompletion/Basic.lean index a680f5898fdf6..62028936b50db 100644 --- a/Mathlib/RingTheory/AdicCompletion/Basic.lean +++ b/Mathlib/RingTheory/AdicCompletion/Basic.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Judith Ludwig, Christian Merten -/ import Mathlib.Algebra.GeomSum import Mathlib.LinearAlgebra.SModEq -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Ideal /-! # Completion of a module with respect to an ideal. @@ -29,7 +29,7 @@ suppress_compilation open Submodule -variable {R : Type*} [CommRing R] (I : Ideal R) +variable {R S T : Type*} [CommRing R] (I : Ideal R) variable (M : Type*) [AddCommGroup M] [Module R M] variable {N : Type*} [AddCommGroup N] [Module R N] @@ -202,24 +202,62 @@ instance : Neg (AdicCompletion I M) where instance : Sub (AdicCompletion I M) where sub x y := ⟨x.val - y.val, by simp [x.property, y.property]⟩ -instance : SMul ℕ (AdicCompletion I M) where - smul n x := ⟨n • x.val, by simp [x.property]⟩ +instance instSMul [SMul S R] [SMul S M] [IsScalarTower S R M] : SMul S (AdicCompletion I M) where + smul r x := ⟨r • x.val, by simp [x.property]⟩ + +@[simp, norm_cast] lemma val_zero : (0 : AdicCompletion I M).val = 0 := rfl + +lemma val_zero_apply (n : ℕ) : (0 : AdicCompletion I M).val n = 0 := rfl + +variable {I M} + +@[simp, norm_cast] lemma val_add (f g : AdicCompletion I M) : (f + g).val = f.val + g.val := rfl +@[simp, norm_cast] lemma val_sub (f g : AdicCompletion I M) : (f - g).val = f.val - g.val := rfl +@[simp, norm_cast] lemma val_neg (f : AdicCompletion I M) : (-f).val = -f.val := rfl + +lemma val_add_apply (f g : AdicCompletion I M) (n : ℕ) : (f + g).val n = f.val n + g.val n := rfl +lemma val_sub_apply (f g : AdicCompletion I M) (n : ℕ) : (f - g).val n = f.val n - g.val n := rfl +lemma val_neg_apply (f : AdicCompletion I M) (n : ℕ) : (-f).val n = -f.val n := rfl + +/- No `simp` attribute, since it causes `simp` unification timeouts when considering +the `Module (AdicCompletion I R) (AdicCompletion I M)` instance (see `AdicCompletion/Algebra`). -/ +@[norm_cast] +lemma val_smul [SMul S R] [SMul S M] [IsScalarTower S R M] (s : S) (f : AdicCompletion I M) : + (s • f).val = s • f.val := rfl + +lemma val_smul_apply [SMul S R] [SMul S M] [IsScalarTower S R M] (s : S) (f : AdicCompletion I M) + (n : ℕ) : (s • f).val n = s • f.val n := rfl + +@[ext] +lemma ext {x y : AdicCompletion I M} (h : ∀ n, x.val n = y.val n) : x = y := Subtype.eq <| funext h -instance : SMul ℤ (AdicCompletion I M) where - smul n x := ⟨n • x.val, by simp [x.property]⟩ +variable (I M) instance : AddCommGroup (AdicCompletion I M) := let f : AdicCompletion I M → ∀ n, M ⧸ (I ^ n • ⊤ : Submodule R M) := Subtype.val - Subtype.val_injective.addCommGroup f rfl (fun _ _ ↦ rfl) (fun _ ↦ rfl) (fun _ _ ↦ rfl) - (fun _ _ ↦ rfl) (fun _ _ ↦ rfl) + Subtype.val_injective.addCommGroup f rfl val_add val_neg val_sub (fun _ _ ↦ val_smul ..) + (fun _ _ ↦ val_smul ..) -instance : SMul R (AdicCompletion I M) where - smul r x := ⟨r • x.val, by simp [x.property]⟩ - -instance : Module R (AdicCompletion I M) := +instance [Semiring S] [SMul S R] [Module S M] [IsScalarTower S R M] : + Module S (AdicCompletion I M) := let f : AdicCompletion I M →+ ∀ n, M ⧸ (I ^ n • ⊤ : Submodule R M) := { toFun := Subtype.val, map_zero' := rfl, map_add' := fun _ _ ↦ rfl } - Subtype.val_injective.module R f (fun _ _ ↦ rfl) + Subtype.val_injective.module S f val_smul + +instance instIsScalarTower [SMul S T] [SMul S R] [SMul T R] [SMul S M] [SMul T M] + [IsScalarTower S R M] [IsScalarTower T R M] [IsScalarTower S T M] : + IsScalarTower S T (AdicCompletion I M) where + smul_assoc s t f := by ext; simp [val_smul] + +instance instSMulCommClass [SMul S R] [SMul T R] [SMul S M] [SMul T M] + [IsScalarTower S R M] [IsScalarTower T R M] [SMulCommClass S T M] : + SMulCommClass S T (AdicCompletion I M) where + smul_comm s t f := by ext; simp [val_smul, smul_comm] + +instance instIsCentralScalar [SMul S R] [SMul Sᵐᵒᵖ R] [SMul S M] [SMul Sᵐᵒᵖ M] + [IsScalarTower S R M] [IsScalarTower Sᵐᵒᵖ R M] [IsCentralScalar S M] : + IsCentralScalar S (AdicCompletion I M) where + op_smul_eq_smul s f := by ext; simp [val_smul, op_smul_eq_smul] /-- The canonical inclusion from the completion to the product. -/ @[simps] @@ -228,6 +266,18 @@ def incl : AdicCompletion I M →ₗ[R] (∀ n, M ⧸ (I ^ n • ⊤ : Submodule map_add' _ _ := rfl map_smul' _ _ := rfl +variable {I M} + +@[simp, norm_cast] +lemma val_sum {ι : Type*} (s : Finset ι) (f : ι → AdicCompletion I M) : + (∑ i ∈ s, f i).val = ∑ i ∈ s, (f i).val := by + simp_rw [← funext (incl_apply _ _ _), map_sum] + +lemma val_sum_apply {ι : Type*} (s : Finset ι) (f : ι → AdicCompletion I M) (n : ℕ) : + (∑ i ∈ s, f i).val n = ∑ i ∈ s, (f i).val n := by simp + +variable (I M) + /-- The canonical linear map to the completion. -/ def of : M →ₗ[R] AdicCompletion I M where toFun x := ⟨fun n => mkQ (I ^ n • ⊤ : Submodule R M) x, fun _ => rfl⟩ @@ -266,43 +316,17 @@ theorem eval_surjective (n : ℕ) : Function.Surjective (eval I M n) := fun x theorem range_eval (n : ℕ) : LinearMap.range (eval I M n) = ⊤ := LinearMap.range_eq_top.2 (eval_surjective I M n) -@[simp] -theorem val_zero (n : ℕ) : (0 : AdicCompletion I M).val n = 0 := - rfl - variable {I M} -@[simp] -theorem val_add (n : ℕ) (f g : AdicCompletion I M) : (f + g).val n = f.val n + g.val n := - rfl - -@[simp] -theorem val_sub (n : ℕ) (f g : AdicCompletion I M) : (f - g).val n = f.val n - g.val n := - rfl - -@[simp] -theorem val_sum {α : Type*} (s : Finset α) (f : α → AdicCompletion I M) (n : ℕ) : - (Finset.sum s f).val n = Finset.sum s (fun a ↦ (f a).val n) := by - simp_rw [← incl_apply, map_sum, Finset.sum_apply] - -/- No `simp` attribute, since it causes `simp` unification timeouts when considering -the `AdicCompletion I R` module instance on `AdicCompletion I M` (see `AdicCompletion/Algebra`). -/ -theorem val_smul (n : ℕ) (r : R) (f : AdicCompletion I M) : (r • f).val n = r • f.val n := - rfl - -@[ext] -theorem ext {x y : AdicCompletion I M} (h : ∀ n, x.val n = y.val n) : x = y := - Subtype.eq <| funext h - variable (I M) instance : IsHausdorff I (AdicCompletion I M) where haus' x h := ext fun n ↦ by refine smul_induction_on (SModEq.zero.1 <| h n) (fun r hr x _ ↦ ?_) (fun x y hx hy ↦ ?_) - · simp only [val_smul, val_zero] + · simp only [val_smul_apply, val_zero] exact Quotient.inductionOn' (x.val n) (fun a ↦ SModEq.zero.2 <| smul_mem_smul hr mem_top) - · simp only [val_add, hx, val_zero, hy, add_zero] + · simp only [val_add_apply, hx, val_zero_apply, hy, add_zero] @[simp] theorem transitionMap_mk {m n : ℕ} (hmn : m ≤ n) (x : M) : diff --git a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean index 03b236a454123..4ac8d7b974ccc 100644 --- a/Mathlib/RingTheory/AdicCompletion/Functoriality.lean +++ b/Mathlib/RingTheory/AdicCompletion/Functoriality.lean @@ -302,7 +302,7 @@ theorem sum_comp_sumInv : sum I M ∘ₗ sumInv I M = LinearMap.id := by simp only [LinearMap.coe_comp, Function.comp_apply, LinearMap.id_coe, id_eq, mk_apply_coe, Submodule.mkQ_apply] rw [← DirectSum.sum_univ_of (((sumInv I M) ((AdicCompletion.mk I (⨁ (j : ι), M j)) f)))] - simp only [sumInv_apply, map_mk, map_sum, sum_of, val_sum, mk_apply_coe, + simp only [sumInv_apply, map_mk, map_sum, sum_of, val_sum_apply, mk_apply_coe, AdicCauchySequence.map_apply_coe, Submodule.mkQ_apply] simp only [← Submodule.mkQ_apply, ← map_sum] erw [DirectSum.sum_univ_of] diff --git a/Mathlib/RingTheory/Adjoin/Basic.lean b/Mathlib/RingTheory/Adjoin/Basic.lean index aa670454a746e..7d4037bf5b2d6 100644 --- a/Mathlib/RingTheory/Adjoin/Basic.lean +++ b/Mathlib/RingTheory/Adjoin/Basic.lean @@ -22,6 +22,7 @@ adjoin, algebra -/ +assert_not_exists Polynomial universe uR uS uA uB @@ -322,6 +323,15 @@ theorem adjoin_adjoin_of_tower (s : Set A) : adjoin S (adjoin R s : Set A) = adj rw [this] exact subset_adjoin +theorem Subalgebra.restrictScalars_adjoin {s : Set A} : + (adjoin S s).restrictScalars R = (IsScalarTower.toAlgHom R S A).range ⊔ adjoin R s := by + refine le_antisymm (fun _ hx ↦ adjoin_induction + (fun x hx ↦ le_sup_right (α := Subalgebra R A) (subset_adjoin hx)) + (fun x ↦ le_sup_left (α := Subalgebra R A) ⟨x, rfl⟩) + (fun _ _ _ _ ↦ add_mem) (fun _ _ _ _ ↦ mul_mem) <| + (Subalgebra.mem_restrictScalars _).mp hx) (sup_le ?_ <| adjoin_le subset_adjoin) + rintro _ ⟨x, rfl⟩; exact algebraMap_mem (adjoin S s) x + @[simp] theorem adjoin_top {A} [Semiring A] [Algebra S A] (t : Set A) : adjoin (⊤ : Subalgebra R S) t = (adjoin S t).restrictScalars (⊤ : Subalgebra R S) := diff --git a/Mathlib/RingTheory/Adjoin/Polynomial.lean b/Mathlib/RingTheory/Adjoin/Polynomial.lean new file mode 100644 index 0000000000000..9a8e63128ef2b --- /dev/null +++ b/Mathlib/RingTheory/Adjoin/Polynomial.lean @@ -0,0 +1,67 @@ +/- +Copyright (c) 2018 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker +-/ +import Mathlib.Algebra.Polynomial.AlgebraMap +import Mathlib.RingTheory.Adjoin.Basic + +/-! +# Polynomials and adjoining roots + +## Main results + +* `Polynomial.instCommSemiringAdjoinSingleton, instCommRingAdjoinSingleton`: + adjoining an element to a commutative (semi)ring gives a commutative (semi)ring +-/ + +noncomputable section + +open Finset + +open Polynomial + +namespace Polynomial + +universe u v w z + +variable {R : Type u} {S : Type v} {T : Type w} {A : Type z} {A' B : Type*} {a b : R} {n : ℕ} + +section aeval + +variable [CommSemiring R] [Semiring A] [CommSemiring A'] [Semiring B] +variable [Algebra R A] [Algebra R B] +variable {p q : R[X]} (x : A) + +@[simp] +theorem adjoin_X : Algebra.adjoin R ({X} : Set R[X]) = ⊤ := by + refine top_unique fun p _hp => ?_ + set S := Algebra.adjoin R ({X} : Set R[X]) + rw [← sum_monomial_eq p]; simp only [← smul_X_eq_monomial, Sum] + exact S.sum_mem fun n _hn => S.smul_mem (S.pow_mem (Algebra.subset_adjoin rfl) _) _ + +variable (R) +theorem _root_.Algebra.adjoin_singleton_eq_range_aeval (x : A) : + Algebra.adjoin R {x} = (Polynomial.aeval x).range := by + rw [← Algebra.map_top, ← adjoin_X, AlgHom.map_adjoin, Set.image_singleton, aeval_X] + +@[simp] +theorem aeval_mem_adjoin_singleton : + aeval x p ∈ Algebra.adjoin R {x} := by + simpa only [Algebra.adjoin_singleton_eq_range_aeval] using Set.mem_range_self p + +instance instCommSemiringAdjoinSingleton : + CommSemiring <| Algebra.adjoin R {x} := + { mul_comm := fun ⟨p, hp⟩ ⟨q, hq⟩ ↦ by + obtain ⟨p', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hp + obtain ⟨q', rfl⟩ := Algebra.adjoin_singleton_eq_range_aeval R x ▸ hq + simp only [AlgHom.toRingHom_eq_coe, RingHom.coe_coe, MulMemClass.mk_mul_mk, ← map_mul, + mul_comm p' q'] } + +instance instCommRingAdjoinSingleton {R A : Type*} [CommRing R] [Ring A] [Algebra R A] (x : A) : + CommRing <| Algebra.adjoin R {x} := + { mul_comm := mul_comm } + +end aeval + +end Polynomial diff --git a/Mathlib/RingTheory/Adjoin/PowerBasis.lean b/Mathlib/RingTheory/Adjoin/PowerBasis.lean index 2a3bbcac0b345..5b1c9fd4bce17 100644 --- a/Mathlib/RingTheory/Adjoin/PowerBasis.lean +++ b/Mathlib/RingTheory/Adjoin/PowerBasis.lean @@ -94,7 +94,7 @@ theorem repr_gen_pow_isIntegral (hB : IsIntegral R B.gen) [IsDomain S] let Q := X ^ n %ₘ minpoly R B.gen have : B.gen ^ n = aeval B.gen Q := by rw [← @aeval_X_pow R _ _ _ _ B.gen, ← modByMonic_add_div (X ^ n) (minpoly.monic hB)] - simp + simp [Q] by_cases hQ : Q = 0 · simp [this, hQ, isIntegral_zero] have hlt : Q.natDegree < B.dim := by diff --git a/Mathlib/RingTheory/Algebraic.lean b/Mathlib/RingTheory/Algebraic/Basic.lean similarity index 58% rename from Mathlib/RingTheory/Algebraic.lean rename to Mathlib/RingTheory/Algebraic/Basic.lean index deafa7a49ce6a..617f4e02b975c 100644 --- a/Mathlib/RingTheory/Algebraic.lean +++ b/Mathlib/RingTheory/Algebraic/Basic.lean @@ -3,10 +3,11 @@ Copyright (c) 2019 Johan Commelin. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ -import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Basic -import Mathlib.RingTheory.Polynomial.IntegralNormalization -import Mathlib.RingTheory.LocalRing.Basic -import Mathlib.Algebra.MvPolynomial.Supported +import Mathlib.Algebra.Polynomial.Expand +import Mathlib.Algebra.Polynomial.Roots +import Mathlib.RingTheory.Adjoin.Polynomial +import Mathlib.RingTheory.Algebraic.Defs +import Mathlib.RingTheory.Polynomial.Tower /-! # Algebraic elements and algebraic extensions @@ -17,43 +18,39 @@ The main result in this file proves transitivity of algebraicity: a tower of algebraic field extensions is algebraic. -/ - universe u v w -open scoped Classical open Polynomial section variable (R : Type u) {A : Type v} [CommRing R] [Ring A] [Algebra R A] -/-- An element of an R-algebra is algebraic over R if it is a root of a nonzero polynomial -with coefficients in R. -/ -@[stacks 09GC "Algebraic elements"] -def IsAlgebraic (x : A) : Prop := - ∃ p : R[X], p ≠ 0 ∧ aeval x p = 0 - -/-- An element of an R-algebra is transcendental over R if it is not algebraic over R. -/ -def Transcendental (x : A) : Prop := - ¬IsAlgebraic R x - @[nontriviality] theorem is_transcendental_of_subsingleton [Subsingleton R] (x : A) : Transcendental R x := fun ⟨p, h, _⟩ => h <| Subsingleton.elim p 0 variable {R} -/-- An element `x` is transcendental over `R` if and only if for any polynomial `p`, -`Polynomial.aeval x p = 0` implies `p = 0`. This is similar to `algebraicIndependent_iff`. -/ -theorem transcendental_iff {x : A} : - Transcendental R x ↔ ∀ p : R[X], aeval x p = 0 → p = 0 := by - rw [Transcendental, IsAlgebraic, not_exists] - congr! 1; tauto +theorem IsAlgebraic.nontrivial {a : A} (h : IsAlgebraic R a) : Nontrivial R := by + contrapose! h + rw [not_nontrivial_iff_subsingleton] at h + apply is_transcendental_of_subsingleton + +variable (R A) + +theorem Algebra.IsAlgebraic.nontrivial [alg : Algebra.IsAlgebraic R A] : Nontrivial R := + (alg.1 0).nontrivial + +instance (priority := low) Algebra.transcendental_of_subsingleton [Subsingleton R] : + Algebra.Transcendental R A := + ⟨⟨0, is_transcendental_of_subsingleton R 0⟩⟩ -variable (R) in theorem Polynomial.transcendental_X : Transcendental R (X (R := R)) := by simp [transcendental_iff] +variable {R A} + theorem IsAlgebraic.of_aeval {r : A} (f : R[X]) (hf : f.natDegree ≠ 0) (hf' : f.leadingCoeff ∈ nonZeroDivisors R) (H : IsAlgebraic R (aeval r f)) : IsAlgebraic R r := by @@ -96,76 +93,6 @@ theorem Polynomial.transcendental (f : R[X]) (hf : f.natDegree ≠ 0) Transcendental R f := by simpa using (transcendental_X R).aeval f hf hf' -/-- If `E / F` is a field extension, `x` is an element of `E` transcendental over `F`, -then `{(x - a)⁻¹ | a : F}` is linearly independent over `F`. -/ -theorem Transcendental.linearIndependent_sub_inv - {F E : Type*} [Field F] [Field E] [Algebra F E] {x : E} (H : Transcendental F x) : - LinearIndependent F fun a ↦ (x - algebraMap F E a)⁻¹ := by - rw [transcendental_iff] at H - refine linearIndependent_iff'.2 fun s m hm i hi ↦ ?_ - have hnz (a : F) : x - algebraMap F E a ≠ 0 := fun h ↦ - X_sub_C_ne_zero a <| H (.X - .C a) (by simp [h]) - let b := s.prod fun j ↦ x - algebraMap F E j - have h1 : ∀ i ∈ s, m i • (b * (x - algebraMap F E i)⁻¹) = - m i • (s.erase i).prod fun j ↦ x - algebraMap F E j := fun i hi ↦ by - simp_rw [b, ← s.prod_erase_mul _ hi, mul_inv_cancel_right₀ (hnz i)] - replace hm := congr(b * $(hm)) - simp_rw [mul_zero, Finset.mul_sum, mul_smul_comm, Finset.sum_congr rfl h1] at hm - let p : Polynomial F := s.sum fun i ↦ .C (m i) * (s.erase i).prod fun j ↦ .X - .C j - replace hm := congr(Polynomial.aeval i $(H p (by simp_rw [← hm, p, map_sum, map_mul, map_prod, - map_sub, aeval_X, aeval_C, Algebra.smul_def]))) - have h2 : ∀ j ∈ s.erase i, m j * ((s.erase j).prod fun x ↦ i - x) = 0 := fun j hj ↦ by - have := Finset.mem_erase_of_ne_of_mem (Finset.ne_of_mem_erase hj).symm hi - simp_rw [← (s.erase j).prod_erase_mul _ this, sub_self, mul_zero] - simp_rw [map_zero, p, map_sum, map_mul, map_prod, map_sub, aeval_X, - aeval_C, Algebra.id.map_eq_self, ← s.sum_erase_add _ hi, - Finset.sum_eq_zero h2, zero_add] at hm - exact eq_zero_of_ne_zero_of_mul_right_eq_zero (Finset.prod_ne_zero_iff.2 fun j hj ↦ - sub_ne_zero.2 (Finset.ne_of_mem_erase hj).symm) hm - -/-- A subalgebra is algebraic if all its elements are algebraic. -/ -nonrec -def Subalgebra.IsAlgebraic (S : Subalgebra R A) : Prop := - ∀ x ∈ S, IsAlgebraic R x - -variable (R A) - -/-- An algebra is algebraic if all its elements are algebraic. -/ -@[stacks 09GC "Algebraic extensions"] -protected class Algebra.IsAlgebraic : Prop where - isAlgebraic : ∀ x : A, IsAlgebraic R x - -/-- An algebra is transcendental if some element is transcendental. -/ -protected class Algebra.Transcendental : Prop where - transcendental : ∃ x : A, Transcendental R x - -variable {R A} - -lemma Algebra.isAlgebraic_def : Algebra.IsAlgebraic R A ↔ ∀ x : A, IsAlgebraic R x := - ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ - -lemma Algebra.transcendental_def : Algebra.Transcendental R A ↔ ∃ x : A, Transcendental R x := - ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ - -theorem Algebra.transcendental_iff_not_isAlgebraic : - Algebra.Transcendental R A ↔ ¬ Algebra.IsAlgebraic R A := by - simp [isAlgebraic_def, transcendental_def, Transcendental] - -/-- A subalgebra is algebraic if and only if it is algebraic as an algebra. -/ -theorem Subalgebra.isAlgebraic_iff (S : Subalgebra R A) : - S.IsAlgebraic ↔ Algebra.IsAlgebraic R S := by - delta Subalgebra.IsAlgebraic - rw [Subtype.forall', Algebra.isAlgebraic_def] - refine forall_congr' fun x => exists_congr fun p => and_congr Iff.rfl ?_ - have h : Function.Injective S.val := Subtype.val_injective - conv_rhs => rw [← h.eq_iff, map_zero] - rw [← aeval_algHom_apply, S.val_apply] - -/-- An algebra is algebraic if and only if it is algebraic as a subalgebra. -/ -theorem Algebra.isAlgebraic_iff : Algebra.IsAlgebraic R A ↔ (⊤ : Subalgebra R A).IsAlgebraic := by - delta Subalgebra.IsAlgebraic - simp only [Algebra.isAlgebraic_def, Algebra.mem_top, forall_prop_of_true] - theorem isAlgebraic_iff_not_injective {x : A} : IsAlgebraic R x ↔ ¬Function.Injective (Polynomial.aeval x : R[X] →ₐ[R] A) := by simp only [IsAlgebraic, injective_iff_map_eq_zero, not_forall, and_comm, exists_prop] @@ -182,6 +109,17 @@ theorem transcendental_iff_ker_eq_bot {x : A} : Transcendental R x ↔ RingHom.ker (aeval (R := R) x) = ⊥ := by rw [transcendental_iff_injective, RingHom.injective_iff_ker_eq_bot] +theorem Algebra.isAlgebraic_of_not_injective (h : ¬ Function.Injective (algebraMap R A)) : + Algebra.IsAlgebraic R A where + isAlgebraic a := isAlgebraic_iff_not_injective.mpr + fun inj ↦ h <| by convert inj.comp C_injective; ext; simp + +theorem Algebra.injective_of_transcendental [h : Algebra.Transcendental R A] : + Function.Injective (algebraMap R A) := by + rw [transcendental_iff_not_isAlgebraic] at h + contrapose! h + exact isAlgebraic_of_not_injective h + end section zero_ne_one @@ -190,13 +128,6 @@ variable {R : Type u} {S : Type*} {A : Type v} [CommRing R] variable [CommRing S] [Ring A] [Algebra R A] [Algebra R S] [Algebra S A] variable [IsScalarTower R S A] -/-- An integral element of an algebra is algebraic. -/ -theorem IsIntegral.isAlgebraic [Nontrivial R] {x : A} : IsIntegral R x → IsAlgebraic R x := - fun ⟨p, hp, hpx⟩ => ⟨p, hp.ne_zero, hpx⟩ - -instance Algebra.IsIntegral.isAlgebraic [Nontrivial R] [Algebra.IsIntegral R A] : - Algebra.IsAlgebraic R A := ⟨fun a ↦ (Algebra.IsIntegral.isIntegral a).isAlgebraic⟩ - theorem isAlgebraic_zero [Nontrivial R] : IsAlgebraic R (0 : A) := ⟨_, X_ne_zero, aeval_X 0⟩ @@ -225,6 +156,16 @@ theorem isAlgebraic_of_mem_rootSet {R : Type u} {A : Type v} [Field R] [Field A] {p : R[X]} {x : A} (hx : x ∈ p.rootSet A) : IsAlgebraic R x := ⟨p, ne_zero_of_mem_rootSet hx, aeval_eq_zero_of_mem_rootSet hx⟩ +variable (S) in +theorem IsLocalization.isAlgebraic [Nontrivial R] (M : Submonoid R) [IsLocalization M S] : + Algebra.IsAlgebraic R S where + isAlgebraic x := by + obtain rfl | hx := eq_or_ne x 0 + · exact isAlgebraic_zero + have ⟨⟨r, m⟩, h⟩ := surj M x + refine ⟨C m.1 * X - C r, fun eq ↦ hx ?_, by simpa [sub_eq_zero, mul_comm x] using h⟩ + rwa [← eq_mk'_iff_mul_eq, show r = 0 by simpa using congr(coeff $eq 0), mk'_zero] at h + open IsScalarTower protected theorem IsAlgebraic.algebraMap {a : S} : @@ -291,7 +232,7 @@ theorem IsAlgebraic.of_ringHom_of_comp_eq (halg : IsAlgebraic S (g a)) (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : IsAlgebraic R a := by obtain ⟨p, h1, h2⟩ := halg - obtain ⟨q, rfl⟩ := map_surjective f hf p + obtain ⟨q, rfl⟩ := map_surjective (f : R →+* S) hf p refine ⟨q, fun h' ↦ by simp [h'] at h1, hg ?_⟩ change aeval ((g : A →+* B) a) _ = 0 at h2 change (g : A →+* B) _ = _ @@ -414,11 +355,9 @@ instance algebra_isAlgebraic_bot_right [Nontrivial R] : end Subalgebra theorem IsAlgebraic.of_pow {r : A} {n : ℕ} (hn : 0 < n) (ht : IsAlgebraic R (r ^ n)) : - IsAlgebraic R r := by - obtain ⟨p, p_nonzero, hp⟩ := ht - refine ⟨Polynomial.expand _ n p, ?_, ?_⟩ - · rwa [Polynomial.expand_ne_zero hn] - · rwa [Polynomial.expand_aeval n p r] + IsAlgebraic R r := + have ⟨p, p_nonzero, hp⟩ := ht + ⟨_, by rwa [expand_ne_zero hn], by rwa [expand_aeval n p r]⟩ theorem Transcendental.pow {r : A} (ht : Transcendental R r) {n : ℕ} (hn : 0 < n) : Transcendental R (r ^ n) := fun ht' ↦ ht <| ht'.of_pow hn @@ -443,49 +382,6 @@ alias ⟨_, IsAlgebraic.inv⟩ := IsAlgebraic.inv_iff end zero_ne_one -section Field - -variable {K : Type u} {A : Type v} [Field K] [Ring A] [Algebra K A] - -/-- An element of an algebra over a field is algebraic if and only if it is integral. -/ -theorem isAlgebraic_iff_isIntegral {x : A} : IsAlgebraic K x ↔ IsIntegral K x := by - refine ⟨?_, IsIntegral.isAlgebraic⟩ - rintro ⟨p, hp, hpx⟩ - refine ⟨_, monic_mul_leadingCoeff_inv hp, ?_⟩ - rw [← aeval_def, map_mul, hpx, zero_mul] - -protected theorem Algebra.isAlgebraic_iff_isIntegral : - Algebra.IsAlgebraic K A ↔ Algebra.IsIntegral K A := by - rw [Algebra.isAlgebraic_def, Algebra.isIntegral_def, - forall_congr' fun _ ↦ isAlgebraic_iff_isIntegral] - -alias ⟨IsAlgebraic.isIntegral, _⟩ := isAlgebraic_iff_isIntegral - -/-- This used to be an `alias` of `Algebra.isAlgebraic_iff_isIntegral` but that would make -`Algebra.IsAlgebraic K A` an explicit parameter instead of instance implicit. -/ -protected instance Algebra.IsAlgebraic.isIntegral [Algebra.IsAlgebraic K A] : - Algebra.IsIntegral K A := Algebra.isAlgebraic_iff_isIntegral.mp ‹_› - -variable (K) in -theorem Algebra.IsAlgebraic.of_isIntegralClosure (B C : Type*) - [CommRing B] [CommRing C] [Algebra K B] [Algebra K C] [Algebra B C] - [IsScalarTower K B C] [IsIntegralClosure B K C] : Algebra.IsAlgebraic K B := - Algebra.isAlgebraic_iff_isIntegral.mpr (IsIntegralClosure.isIntegral_algebra K C) - -/-- If `K` is a field, `r : A` and `f : K[X]`, then `Polynomial.aeval r f` is -transcendental over `K` if and only if `r` and `f` are both transcendental over `K`. -See also `Transcendental.aeval_of_transcendental` and `Transcendental.of_aeval`. -/ -@[simp] -theorem transcendental_aeval_iff {r : A} {f : K[X]} : - Transcendental K (Polynomial.aeval r f) ↔ Transcendental K r ∧ Transcendental K f := by - refine ⟨fun h ↦ ⟨?_, h.of_aeval⟩, fun ⟨h1, h2⟩ ↦ h1.aeval_of_transcendental h2⟩ - rw [Transcendental] at h ⊢ - contrapose! h - rw [isAlgebraic_iff_isIntegral] at h ⊢ - exact .of_mem_of_fg _ h.fg_adjoin_singleton _ (aeval_mem_adjoin_singleton _ _) - -end Field - section variable {K L R S A : Type*} @@ -572,17 +468,7 @@ theorem Transcendental.of_tower_top {x : A} (h : Transcendental L x) : theorem Algebra.IsAlgebraic.tower_top [Algebra.IsAlgebraic K A] : Algebra.IsAlgebraic L A := Algebra.IsAlgebraic.extendScalars (algebraMap K L).injective -variable (K) - -theorem IsAlgebraic.of_finite (e : A) [FiniteDimensional K A] : IsAlgebraic K e := - (IsIntegral.of_finite K e).isAlgebraic - -variable (A) - -/-- A field extension is algebraic if it is finite. -/ -@[stacks 09GG "first part"] -instance Algebra.IsAlgebraic.of_finite [FiniteDimensional K A] : Algebra.IsAlgebraic K A := - (IsIntegral.of_finite K A).isAlgebraic +variable (K) (A) theorem Algebra.IsAlgebraic.tower_bot (K L A : Type*) [CommRing K] [Field L] [Ring A] [Algebra K L] [Algebra L A] [Algebra K A] [IsScalarTower K L A] @@ -594,28 +480,11 @@ end Field end Ring -section CommRing - -variable [Field K] [Field L] [Ring A] -variable [Algebra K L] [Algebra L A] [Algebra K A] [IsScalarTower K L A] - -/-- If L is an algebraic field extension of K and A is an algebraic algebra over L, -then A is algebraic over K. -/ -@[stacks 09GJ] -protected theorem Algebra.IsAlgebraic.trans - [L_alg : Algebra.IsAlgebraic K L] [A_alg : Algebra.IsAlgebraic L A] : - Algebra.IsAlgebraic K A := by - rw [Algebra.isAlgebraic_iff_isIntegral] at L_alg A_alg ⊢ - exact Algebra.IsIntegral.trans L - -end CommRing - section NoZeroSMulDivisors namespace Algebra.IsAlgebraic -variable [CommRing K] [Field L] -variable [Algebra K L] +variable [CommRing K] [Field L] [Algebra K L] theorem algHom_bijective [NoZeroSMulDivisors K L] [Algebra.IsAlgebraic K L] (f : L →ₐ[K] L) : Function.Bijective f := by @@ -659,23 +528,6 @@ end Algebra.IsAlgebraic end NoZeroSMulDivisors -section Field - -variable [Field K] [Field L] -variable [Algebra K L] - -theorem AlgHom.bijective [FiniteDimensional K L] (ϕ : L →ₐ[K] L) : Function.Bijective ϕ := - (Algebra.IsAlgebraic.of_finite K L).algHom_bijective ϕ - -variable (K L) - -/-- Bijection between algebra equivalences and algebra homomorphisms -/ -noncomputable abbrev algEquivEquivAlgHom [FiniteDimensional K L] : - (L ≃ₐ[K] L) ≃* (L →ₐ[K] L) := - Algebra.IsAlgebraic.algEquivEquivAlgHom K L - -end Field - end section @@ -684,53 +536,49 @@ variable {R S : Type*} [CommRing R] [Ring S] [Algebra R S] theorem IsAlgebraic.exists_nonzero_coeff_and_aeval_eq_zero {s : S} (hRs : IsAlgebraic R s) (hs : s ∈ nonZeroDivisors S) : - ∃ (q : Polynomial R), q.coeff 0 ≠ 0 ∧ aeval s q = 0 := by + ∃ q : R[X], q.coeff 0 ≠ 0 ∧ aeval s q = 0 := by obtain ⟨p, hp0, hp⟩ := hRs - obtain ⟨q, hpq, hq⟩ := Polynomial.exists_eq_pow_rootMultiplicity_mul_and_not_dvd p hp0 0 + obtain ⟨q, hpq, hq⟩ := exists_eq_pow_rootMultiplicity_mul_and_not_dvd p hp0 0 simp only [C_0, sub_zero, X_pow_mul, X_dvd_iff] at hpq hq rw [hpq, map_mul, aeval_X_pow] at hp exact ⟨q, hq, (nonZeroDivisors S).pow_mem hs (rootMultiplicity 0 p) (aeval s q) hp⟩ +theorem IsAlgebraic.exists_nonzero_eq_adjoin_mul + {s : S} (hRs : IsAlgebraic R s) (hs : s ∈ nonZeroDivisors S) : + ∃ᵉ (t ∈ Algebra.adjoin R {s}) (r ≠ (0 : R)), s * t = algebraMap R S r := by + have ⟨q, hq0, hq⟩ := hRs.exists_nonzero_coeff_and_aeval_eq_zero hs + have ⟨p, hp⟩ := X_dvd_sub_C (p := q) + refine ⟨aeval s p, aeval_mem_adjoin_singleton _ _, _, neg_ne_zero.mpr hq0, ?_⟩ + apply_fun aeval s at hp + rwa [map_sub, hq, zero_sub, map_mul, aeval_X, aeval_C, ← map_neg, eq_comm] at hp + theorem IsAlgebraic.exists_nonzero_dvd {s : S} (hRs : IsAlgebraic R s) (hs : s ∈ nonZeroDivisors S) : - ∃ r : R, r ≠ 0 ∧ s ∣ (algebraMap R S) r := by + ∃ r : R, r ≠ 0 ∧ s ∣ algebraMap R S r := by obtain ⟨q, hq0, hq⟩ := hRs.exists_nonzero_coeff_and_aeval_eq_zero hs - have key := map_dvd (Polynomial.aeval s) (Polynomial.X_dvd_sub_C (p := q)) - rw [map_sub, hq, zero_sub, dvd_neg, Polynomial.aeval_X, Polynomial.aeval_C] at key + have key := map_dvd (aeval s) (X_dvd_sub_C (p := q)) + rw [map_sub, hq, zero_sub, dvd_neg, aeval_X, aeval_C] at key exact ⟨q.coeff 0, hq0, key⟩ /-- A fraction `(a : S) / (b : S)` can be reduced to `(c : S) / (d : R)`, if `b` is algebraic over `R`. -/ theorem IsAlgebraic.exists_smul_eq_mul (a : S) {b : S} (hRb : IsAlgebraic R b) (hb : b ∈ nonZeroDivisors S) : - ∃ᵉ (c : S) (d ≠ (0 : R)), d • a = b * c := by - obtain ⟨r, hr, s, h⟩ := IsAlgebraic.exists_nonzero_dvd (R := R) (S := S) hRb hb - exact ⟨s * a, r, hr, by rw [Algebra.smul_def, h, mul_assoc]⟩ + ∃ᵉ (c : S) (d ≠ (0 : R)), d • a = b * c := + have ⟨r, hr, s, h⟩ := hRb.exists_nonzero_dvd hb + ⟨s * a, r, hr, by rw [Algebra.smul_def, h, mul_assoc]⟩ variable (R) /-- A fraction `(a : S) / (b : S)` can be reduced to `(c : S) / (d : R)`, if `b` is algebraic over `R`. -/ -theorem Algebra.IsAlgebraic.exists_smul_eq_mul [IsDomain S] [Algebra.IsAlgebraic R S] +theorem Algebra.IsAlgebraic.exists_smul_eq_mul [NoZeroDivisors S] [Algebra.IsAlgebraic R S] (a : S) {b : S} (hb : b ≠ 0) : ∃ᵉ (c : S) (d ≠ (0 : R)), d • a = b * c := - (Algebra.IsAlgebraic.isAlgebraic b).exists_smul_eq_mul a (mem_nonZeroDivisors_iff_ne_zero.mpr hb) + (isAlgebraic b).exists_smul_eq_mul a (mem_nonZeroDivisors_of_ne_zero hb) end -variable {R S : Type*} [CommRing R] [IsDomain R] [CommRing S] - -theorem exists_integral_multiple [Algebra R S] {z : S} (hz : IsAlgebraic R z) - (inj : ∀ x, algebraMap R S x = 0 → x = 0) : - ∃ᵉ (x : integralClosure R S) (y ≠ (0 : R)), z * algebraMap R S y = x := by - rcases hz with ⟨p, p_ne_zero, px⟩ - set a := p.leadingCoeff - have a_ne_zero : a ≠ 0 := mt Polynomial.leadingCoeff_eq_zero.mp p_ne_zero - have x_integral : IsIntegral R (z * algebraMap R S a) := - ⟨p.integralNormalization, monic_integralNormalization p_ne_zero, - integralNormalization_aeval_eq_zero px inj⟩ - exact ⟨⟨_, x_integral⟩, a, a_ne_zero, rfl⟩ - section Field variable {K L : Type*} [Field K] [Field L] [Algebra K L] (A : Subalgebra K L) @@ -792,174 +640,15 @@ theorem Subalgebra.isField_of_algebraic [Algebra.IsAlgebraic K L] : IsField A := end Field -section Pi - -variable (R' : Type u) (S' : Type v) (T' : Type w) - -/-- This is not an instance as it forms a diamond with `Pi.instSMul`. - -See the `instance_diamonds` test for details. -/ -def Polynomial.hasSMulPi [Semiring R'] [SMul R' S'] : SMul R'[X] (R' → S') := - ⟨fun p f x => eval x p • f x⟩ - -/-- This is not an instance as it forms a diamond with `Pi.instSMul`. - -See the `instance_diamonds` test for details. -/ -noncomputable def Polynomial.hasSMulPi' [CommSemiring R'] [Semiring S'] [Algebra R' S'] - [SMul S' T'] : SMul R'[X] (S' → T') := - ⟨fun p f x => aeval x p • f x⟩ - -attribute [local instance] Polynomial.hasSMulPi Polynomial.hasSMulPi' - -@[simp] -theorem polynomial_smul_apply [Semiring R'] [SMul R' S'] (p : R'[X]) (f : R' → S') (x : R') : - (p • f) x = eval x p • f x := - rfl - -@[simp] -theorem polynomial_smul_apply' [CommSemiring R'] [Semiring S'] [Algebra R' S'] [SMul S' T'] - (p : R'[X]) (f : S' → T') (x : S') : (p • f) x = aeval x p • f x := - rfl - -variable [CommSemiring R'] [CommSemiring S'] [CommSemiring T'] [Algebra R' S'] [Algebra S' T'] - --- Porting note: the proofs in this definition used `funext` in term-mode, but I was not able --- to get them to work anymore. -/-- This is not an instance for the same reasons as `Polynomial.hasSMulPi'`. -/ -noncomputable def Polynomial.algebraPi : Algebra R'[X] (S' → T') := - { Polynomial.hasSMulPi' R' S' T' with - toFun := fun p z => algebraMap S' T' (aeval z p) - map_one' := by - funext z - simp only [Polynomial.aeval_one, Pi.one_apply, map_one] - map_mul' := fun f g => by - funext z - simp only [Pi.mul_apply, map_mul] - map_zero' := by - funext z - simp only [Polynomial.aeval_zero, Pi.zero_apply, map_zero] - map_add' := fun f g => by - funext z - simp only [Polynomial.aeval_add, Pi.add_apply, map_add] - commutes' := fun p f => by - funext z - exact mul_comm _ _ - smul_def' := fun p f => by - funext z - simp only [polynomial_smul_apply', Algebra.algebraMap_eq_smul_one, RingHom.coe_mk, - MonoidHom.coe_mk, OneHom.coe_mk, Pi.mul_apply, Algebra.smul_mul_assoc, one_mul] } - -attribute [local instance] Polynomial.algebraPi - -@[simp] -theorem Polynomial.algebraMap_pi_eq_aeval : - (algebraMap R'[X] (S' → T') : R'[X] → S' → T') = fun p z => algebraMap _ _ (aeval z p) := - rfl - -@[simp] -theorem Polynomial.algebraMap_pi_self_eq_eval : - (algebraMap R'[X] (R' → R') : R'[X] → R' → R') = fun p z => eval z p := - rfl - -end Pi - -namespace MvPolynomial - -variable {σ : Type*} (R : Type*) [CommRing R] - --- TODO: move to suitable place -private theorem rename_polynomial_aeval_X - {σ τ R : Type*} [CommSemiring R] (f : σ → τ) (i : σ) (p : R[X]) : - rename f (Polynomial.aeval (X i) p) = Polynomial.aeval (X (f i) : MvPolynomial τ R) p := by - rw [← AlgHom.comp_apply] - congr 1; ext1; simp - -theorem transcendental_supported_polynomial_aeval_X {i : σ} {s : Set σ} (h : i ∉ s) - {f : R[X]} (hf : Transcendental R f) : - Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) := by - rw [transcendental_iff_injective] at hf ⊢ - let g := MvPolynomial.mapAlgHom (R := R) (σ := s) (Polynomial.aeval (R := R) f) - replace hf : Function.Injective g := MvPolynomial.map_injective _ hf - let u := (Subalgebra.val _).comp - ((optionEquivRight R s).symm |>.trans - (renameEquiv R (Set.subtypeInsertEquivOption h).symm) |>.trans - (supportedEquivMvPolynomial _).symm).toAlgHom |>.comp - g |>.comp - ((optionEquivLeft R s).symm.trans (optionEquivRight R s)).toAlgHom - let v := ((Polynomial.aeval (R := supported R s) - (Polynomial.aeval (X i : MvPolynomial σ R) f)).restrictScalars R).comp - (Polynomial.mapAlgEquiv (supportedEquivMvPolynomial s).symm).toAlgHom - replace hf : Function.Injective u := by - simp only [AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, Subalgebra.coe_val, - AlgHom.coe_coe, AlgEquiv.coe_trans, Function.comp_assoc, u] - apply Subtype.val_injective.comp - simp only [EquivLike.comp_injective] - apply hf.comp - simp only [EquivLike.comp_injective, EquivLike.injective] - have h1 : Polynomial.aeval (X i : MvPolynomial σ R) = ((Subalgebra.val _).comp - (supportedEquivMvPolynomial _).symm.toAlgHom |>.comp - (Polynomial.aeval (X ⟨i, s.mem_insert i⟩ : MvPolynomial ↑(insert i s) R))) := by - ext1; simp - have h2 : u = v := by - simp only [u, v, g] - ext1 - · ext1 - simp [Set.subtypeInsertEquivOption, Subalgebra.algebraMap_eq] - · simp [Set.subtypeInsertEquivOption, rename_polynomial_aeval_X, h1] - simpa only [h2, v, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, AlgHom.coe_coe, - EquivLike.injective_comp, AlgHom.coe_restrictScalars'] using hf - -theorem transcendental_polynomial_aeval_X (i : σ) {f : R[X]} (hf : Transcendental R f) : - Transcendental R (Polynomial.aeval (X i : MvPolynomial σ R) f) := by - have := transcendental_supported_polynomial_aeval_X R (Set.not_mem_empty i) hf - let g := (Algebra.botEquivOfInjective (MvPolynomial.C_injective σ R)).symm.trans - (Subalgebra.equivOfEq _ _ supported_empty).symm - rwa [Transcendental, ← isAlgebraic_ringHom_iff_of_comp_eq g (RingHom.id (MvPolynomial σ R)) - Function.injective_id (by ext1; rfl), RingHom.id_apply, ← Transcendental] - -theorem transcendental_polynomial_aeval_X_iff (i : σ) {f : R[X]} : - Transcendental R (Polynomial.aeval (X i : MvPolynomial σ R) f) ↔ Transcendental R f := by - refine ⟨?_, transcendental_polynomial_aeval_X R i⟩ - simp_rw [Transcendental, not_imp_not] - exact fun h ↦ h.algHom _ - -theorem transcendental_supported_polynomial_aeval_X_iff - [Nontrivial R] {i : σ} {s : Set σ} {f : R[X]} : - Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) ↔ - i ∉ s ∧ Transcendental R f := by - refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨h, hf⟩ ↦ transcendental_supported_polynomial_aeval_X R h hf⟩ - · rw [Transcendental] at h - contrapose! h - refine isAlgebraic_algebraMap (⟨Polynomial.aeval (X i) f, ?_⟩ : supported R s) - exact Algebra.adjoin_mono (Set.singleton_subset_iff.2 (Set.mem_image_of_mem _ h)) - (Polynomial.aeval_mem_adjoin_singleton _ _) - · rw [← transcendental_polynomial_aeval_X_iff R i] - refine h.restrictScalars fun _ _ heq ↦ MvPolynomial.C_injective σ R ?_ - simp_rw [← MvPolynomial.algebraMap_eq] - exact congr($(heq).1) - -theorem transcendental_supported_X {i : σ} {s : Set σ} (h : i ∉ s) : - Transcendental (supported R s) (X i : MvPolynomial σ R) := by - simpa using transcendental_supported_polynomial_aeval_X R h (Polynomial.transcendental_X R) - -theorem transcendental_X (i : σ) : Transcendental R (X i : MvPolynomial σ R) := by - simpa using transcendental_polynomial_aeval_X R i (Polynomial.transcendental_X R) - -theorem transcendental_supported_X_iff [Nontrivial R] {i : σ} {s : Set σ} : - Transcendental (supported R s) (X i : MvPolynomial σ R) ↔ i ∉ s := by - simpa [Polynomial.transcendental_X] using - transcendental_supported_polynomial_aeval_X_iff R (i := i) (s := s) (f := Polynomial.X) - -end MvPolynomial - section Infinite -theorem Transcendental.infinite {R A : Type*} [CommRing R] [Ring A] [Algebra R A] - [Nontrivial R] {x : A} (hx : Transcendental R x) : Infinite A := +variable {R A : Type*} [CommRing R] [Ring A] [Algebra R A] [Nontrivial R] + +theorem Transcendental.infinite {x : A} (hx : Transcendental R x) : Infinite A := .of_injective _ (transcendental_iff_injective.mp hx) -theorem Algebra.Transcendental.infinite (R A : Type*) [CommRing R] [Ring A] [Algebra R A] - [Nontrivial R] [Algebra.Transcendental R A] : Infinite A := +variable (R A) in +theorem Algebra.Transcendental.infinite [Algebra.Transcendental R A] : Infinite A := have ⟨x, hx⟩ := ‹Algebra.Transcendental R A› hx.infinite diff --git a/Mathlib/RingTheory/Algebraic/Cardinality.lean b/Mathlib/RingTheory/Algebraic/Cardinality.lean index 43311bc18a58e..84f3f265104fc 100644 --- a/Mathlib/RingTheory/Algebraic/Cardinality.lean +++ b/Mathlib/RingTheory/Algebraic/Cardinality.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ import Mathlib.Algebra.Polynomial.Cardinal -import Mathlib.RingTheory.Algebraic +import Mathlib.Algebra.Polynomial.Roots +import Mathlib.RingTheory.Algebraic.Defs /-! # Cardinality of algebraic extensions diff --git a/Mathlib/RingTheory/Algebraic/Defs.lean b/Mathlib/RingTheory/Algebraic/Defs.lean new file mode 100644 index 0000000000000..90f80b749d130 --- /dev/null +++ b/Mathlib/RingTheory/Algebraic/Defs.lean @@ -0,0 +1,103 @@ +/- +Copyright (c) 2019 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.Algebra.Polynomial.AlgebraMap + +/-! +# Algebraic elements and algebraic extensions + +An element of an R-algebra is algebraic over R if it is the root of a nonzero polynomial. +An R-algebra is algebraic over R if and only if all its elements are algebraic over R. + +## Main definitions + +* `IsAlgebraic`: algebraic elements of an algebra. +* `Transcendental`: transcendental elements of an algebra are those that are not algebraic. +* `Subalgebra.IsAlgebraic`: a subalgebra is algebraic if all its elements are algebraic. +* `Algebra.IsAlgebraic`: an algebra is algebraic if all its elements are algebraic. +* `Algebra.Transcendental`: an algebra is transcendental if some element is transcendental. + +## Main results + +* `transcendental_iff`: an element `x : A` is transcendental over `R` iff out of `R[X]` + only the zero polynomial evaluates to 0 at `x`. +* `Subalgebra.isAlgebraic_iff`: a subalgebra is algebraic iff it is algebraic as an algebra. +-/ + +assert_not_exists IsIntegralClosure +assert_not_exists LinearIndependent +assert_not_exists LocalRing +assert_not_exists MvPolynomial + +universe u v w +open Polynomial + +section + +variable (R : Type u) {A : Type v} [CommRing R] [Ring A] [Algebra R A] + +/-- An element of an R-algebra is algebraic over R if it is a root of a nonzero polynomial +with coefficients in R. -/ +@[stacks 09GC "Algebraic elements"] +def IsAlgebraic (x : A) : Prop := + ∃ p : R[X], p ≠ 0 ∧ aeval x p = 0 + +/-- An element of an R-algebra is transcendental over R if it is not algebraic over R. -/ +def Transcendental (x : A) : Prop := + ¬IsAlgebraic R x + +variable {R} + +/-- An element `x` is transcendental over `R` if and only if for any polynomial `p`, +`Polynomial.aeval x p = 0` implies `p = 0`. This is similar to `algebraicIndependent_iff`. -/ +theorem transcendental_iff {x : A} : + Transcendental R x ↔ ∀ p : R[X], aeval x p = 0 → p = 0 := by + rw [Transcendental, IsAlgebraic, not_exists] + congr! 1; tauto + +/-- A subalgebra is algebraic if all its elements are algebraic. -/ +nonrec +def Subalgebra.IsAlgebraic (S : Subalgebra R A) : Prop := + ∀ x ∈ S, IsAlgebraic R x + +variable (R A) + +/-- An algebra is algebraic if all its elements are algebraic. -/ +@[stacks 09GC "Algebraic extensions"] +protected class Algebra.IsAlgebraic : Prop where + isAlgebraic : ∀ x : A, IsAlgebraic R x + +/-- An algebra is transcendental if some element is transcendental. -/ +protected class Algebra.Transcendental : Prop where + transcendental : ∃ x : A, Transcendental R x + +variable {R A} + +lemma Algebra.isAlgebraic_def : Algebra.IsAlgebraic R A ↔ ∀ x : A, IsAlgebraic R x := + ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + +lemma Algebra.transcendental_def : Algebra.Transcendental R A ↔ ∃ x : A, Transcendental R x := + ⟨fun ⟨h⟩ ↦ h, fun h ↦ ⟨h⟩⟩ + +theorem Algebra.transcendental_iff_not_isAlgebraic : + Algebra.Transcendental R A ↔ ¬ Algebra.IsAlgebraic R A := by + simp [isAlgebraic_def, transcendental_def, Transcendental] + +/-- A subalgebra is algebraic if and only if it is algebraic as an algebra. -/ +theorem Subalgebra.isAlgebraic_iff (S : Subalgebra R A) : + S.IsAlgebraic ↔ Algebra.IsAlgebraic R S := by + delta Subalgebra.IsAlgebraic + rw [Subtype.forall', Algebra.isAlgebraic_def] + refine forall_congr' fun x => exists_congr fun p => and_congr Iff.rfl ?_ + have h : Function.Injective S.val := Subtype.val_injective + conv_rhs => rw [← h.eq_iff, map_zero] + rw [← aeval_algHom_apply, S.val_apply] + +/-- An algebra is algebraic if and only if it is algebraic as a subalgebra. -/ +theorem Algebra.isAlgebraic_iff : Algebra.IsAlgebraic R A ↔ (⊤ : Subalgebra R A).IsAlgebraic := by + delta Subalgebra.IsAlgebraic + simp only [Algebra.isAlgebraic_def, Algebra.mem_top, forall_prop_of_true] + +end diff --git a/Mathlib/RingTheory/Algebraic/Integral.lean b/Mathlib/RingTheory/Algebraic/Integral.lean new file mode 100644 index 0000000000000..5a9c3fa6e04f6 --- /dev/null +++ b/Mathlib/RingTheory/Algebraic/Integral.lean @@ -0,0 +1,404 @@ +/- +Copyright (c) 2019 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.RingTheory.Algebraic.Basic +import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Basic + +/-! +# Algebraic elements and integral elements + +This file relates algebraic and integral elements of an algebra, by proving every integral element +is algebraic and that every algebraic element over a field is integral. + +## Main results + +* `IsIntegral.isAlgebraic`, `Algebra.IsIntegral.isAlgebraic`: integral implies algebraic. +* `isAlgebraic_iff_isIntegral`, `Algebra.isAlgebraic_iff_isIntegral`: integral iff algebraic + over a field. +* `IsAlgebraic.of_finite`, `Algebra.IsAlgebraic.of_finite`: finite-dimensional (as module) implies + algebraic. +* `IsAlgebraic.exists_integral_multiple`: an algebraic element has a multiple which is integral +* `IsAlgebraic.iff_exists_smul_integral`: If `R` is reduced and `S` is an `R`-algebra with + injective `algebraMap`, then an element of `S` is algebraic over `R` iff some `R`-multiple + is integral over `R`. +* `Algebra.IsAlgebraic.trans'`: If `A/S/R` is a tower of algebras and both `A/S` and `S/R` are + algebraic, then `A/R` is also algebraic, provided that `S` has no zero divisors and + `algebraMap S A` is injective (so `S` can be regarded as an `R`-subalgebra of `A`). +* `Subalgebra.algebraicClosure`: If `R` is a domain and `S` is an arbitrary `R`-algebra, + then the elements of `S` that are algebraic over `R` form a subalgebra. +* `Transcendental.extendScalars`: an element of an `R`-algebra that is transcendental over `R` + remains transcendental over any algebraic `R`-subalgebra that has no zero divisors. +-/ + +assert_not_exists LocalRing + +universe u v w + +open Polynomial + +section zero_ne_one + +variable {R : Type u} {S : Type*} {A : Type v} [CommRing R] +variable [CommRing S] [Ring A] [Algebra R A] [Algebra R S] [Algebra S A] +variable [IsScalarTower R S A] + +/-- An integral element of an algebra is algebraic. -/ +theorem IsIntegral.isAlgebraic [Nontrivial R] {x : A} : IsIntegral R x → IsAlgebraic R x := + fun ⟨p, hp, hpx⟩ => ⟨p, hp.ne_zero, hpx⟩ + +instance Algebra.IsIntegral.isAlgebraic [Nontrivial R] [Algebra.IsIntegral R A] : + Algebra.IsAlgebraic R A := ⟨fun a ↦ (Algebra.IsIntegral.isIntegral a).isAlgebraic⟩ + +end zero_ne_one + +section Field + +variable {K : Type u} {A : Type v} [Field K] [Ring A] [Algebra K A] + +/-- An element of an algebra over a field is algebraic if and only if it is integral. -/ +theorem isAlgebraic_iff_isIntegral {x : A} : IsAlgebraic K x ↔ IsIntegral K x := by + refine ⟨?_, IsIntegral.isAlgebraic⟩ + rintro ⟨p, hp, hpx⟩ + refine ⟨_, monic_mul_leadingCoeff_inv hp, ?_⟩ + rw [← aeval_def, map_mul, hpx, zero_mul] + +protected theorem Algebra.isAlgebraic_iff_isIntegral : + Algebra.IsAlgebraic K A ↔ Algebra.IsIntegral K A := by + rw [Algebra.isAlgebraic_def, Algebra.isIntegral_def, + forall_congr' fun _ ↦ isAlgebraic_iff_isIntegral] + +alias ⟨IsAlgebraic.isIntegral, _⟩ := isAlgebraic_iff_isIntegral + +/-- This used to be an `alias` of `Algebra.isAlgebraic_iff_isIntegral` but that would make +`Algebra.IsAlgebraic K A` an explicit parameter instead of instance implicit. -/ +protected instance Algebra.IsAlgebraic.isIntegral [Algebra.IsAlgebraic K A] : + Algebra.IsIntegral K A := Algebra.isAlgebraic_iff_isIntegral.mp ‹_› + +theorem Algebra.IsAlgebraic.of_isIntegralClosure (R B C : Type*) [CommRing R] [Nontrivial R] + [CommRing B] [CommRing C] [Algebra R B] [Algebra R C] [Algebra B C] + [IsScalarTower R B C] [IsIntegralClosure B R C] : Algebra.IsAlgebraic R B := + have := IsIntegralClosure.isIntegral_algebra R (A := B) C + inferInstance + +end Field + +section + +variable (K L : Type*) {R S A : Type*} + +section Ring + +section Field + +variable [Field K] [Field L] [Ring A] +variable [Algebra K L] [Algebra L A] [Algebra K A] [IsScalarTower K L A] + +theorem IsAlgebraic.of_finite (e : A) [FiniteDimensional K A] : IsAlgebraic K e := + (IsIntegral.of_finite K e).isAlgebraic + +variable (A) + +/-- A field extension is algebraic if it is finite. -/ +@[stacks 09GG "first part"] +instance Algebra.IsAlgebraic.of_finite [FiniteDimensional K A] : Algebra.IsAlgebraic K A := + (IsIntegral.of_finite K A).isAlgebraic + +end Field + +end Ring + +section CommRing + +variable {K L} [Field K] [Field L] [Ring A] +variable [Algebra K L] [Algebra L A] [Algebra K A] [IsScalarTower K L A] + +/-- If L is an algebraic field extension of K and A is an algebraic algebra over L, +then A is algebraic over K. -/ +@[stacks 09GJ] +protected theorem Algebra.IsAlgebraic.trans + [L_alg : Algebra.IsAlgebraic K L] [A_alg : Algebra.IsAlgebraic L A] : + Algebra.IsAlgebraic K A := by + rw [Algebra.isAlgebraic_iff_isIntegral] at L_alg A_alg ⊢ + exact Algebra.IsIntegral.trans L + +end CommRing + +section Field + +variable {K L} [Field K] [Ring A] [Algebra K A] + +/-- If `K` is a field, `r : A` and `f : K[X]`, then `Polynomial.aeval r f` is +transcendental over `K` if and only if `r` and `f` are both transcendental over `K`. +See also `Transcendental.aeval_of_transcendental` and `Transcendental.of_aeval`. -/ +@[simp] +theorem transcendental_aeval_iff {r : A} {f : K[X]} : + Transcendental K (Polynomial.aeval r f) ↔ Transcendental K r ∧ Transcendental K f := by + refine ⟨fun h ↦ ⟨?_, h.of_aeval⟩, fun ⟨h1, h2⟩ ↦ h1.aeval_of_transcendental h2⟩ + rw [Transcendental] at h ⊢ + contrapose! h + rw [isAlgebraic_iff_isIntegral] at h ⊢ + exact .of_mem_of_fg _ h.fg_adjoin_singleton _ (aeval_mem_adjoin_singleton _ _) + +variable [Field L] [Algebra K L] + +theorem AlgHom.bijective [FiniteDimensional K L] (ϕ : L →ₐ[K] L) : Function.Bijective ϕ := + (Algebra.IsAlgebraic.of_finite K L).algHom_bijective ϕ + +variable (K L) in +/-- Bijection between algebra equivalences and algebra homomorphisms -/ +noncomputable abbrev algEquivEquivAlgHom [FiniteDimensional K L] : + (L ≃ₐ[K] L) ≃* (L →ₐ[K] L) := + Algebra.IsAlgebraic.algEquivEquivAlgHom K L + +end Field + +end + +variable {R S A : Type*} [CommRing R] [CommRing S] [Ring A] +variable [Algebra R S] [Algebra R A] [Algebra S A] [IsScalarTower R S A] +variable {z : A} {z' : S} + +namespace IsAlgebraic + +theorem exists_integral_multiple (hz : IsAlgebraic R z) + (inj : Function.Injective (algebraMap R A)) : + ∃ y ≠ (0 : R), IsIntegral R (y • z) := by + have ⟨p, p_ne_zero, px⟩ := hz + set a := p.leadingCoeff + have a_ne_zero : a ≠ 0 := mt Polynomial.leadingCoeff_eq_zero.mp p_ne_zero + have x_integral : IsIntegral R (algebraMap R A a * z) := + ⟨p.integralNormalization, monic_integralNormalization p_ne_zero, + integralNormalization_aeval_eq_zero px fun _ ↦ (map_eq_zero_iff _ inj).mp⟩ + exact ⟨_, a_ne_zero, Algebra.smul_def a z ▸ x_integral⟩ + +@[deprecated (since := "2024-11-30")] +alias _root_.exists_integral_multiple := exists_integral_multiple + +theorem _root_.Algebra.IsAlgebraic.exists_integral_multiples [NoZeroDivisors R] + [alg : Algebra.IsAlgebraic R A] (inj : Function.Injective (algebraMap R A)) (s : Finset A) : + ∃ y ≠ (0 : R), ∀ z ∈ s, IsIntegral R (y • z) := by + have := Algebra.IsAlgebraic.nontrivial R A + choose r hr int using fun x ↦ (alg.1 x).exists_integral_multiple inj + refine ⟨∏ x ∈ s, r x, Finset.prod_ne_zero_iff.mpr fun _ _ ↦ hr _, fun _ h ↦ ?_⟩ + classical rw [← Finset.prod_erase_mul _ _ h, mul_smul] + exact (int _).smul _ + +theorem of_smul_isIntegral {y : R} (hy : ¬ IsNilpotent y) + (h : IsIntegral R (y • z)) : IsAlgebraic R z := by + have ⟨p, monic, eval0⟩ := h + refine ⟨p.comp (C y * X), fun h ↦ ?_, by simpa [aeval_comp, Algebra.smul_def] using eval0⟩ + apply_fun (coeff · p.natDegree) at h + have hy0 : y ≠ 0 := by rintro rfl; exact hy .zero + rw [coeff_zero, ← mul_one p.natDegree, ← natDegree_C_mul_X y hy0, + coeff_comp_degree_mul_degree, monic, one_mul, leadingCoeff_C_mul_X] at h + · exact hy ⟨_, h⟩ + · rw [natDegree_C_mul_X _ hy0]; rintro ⟨⟩ + +theorem of_smul {y : R} (hy : y ∈ nonZeroDivisors R) + (h : IsAlgebraic R (y • z)) : IsAlgebraic R z := + have ⟨p, hp, eval0⟩ := h + ⟨_, mt (comp_C_mul_X_eq_zero_iff hy).mp hp, by simpa [aeval_comp, Algebra.smul_def] using eval0⟩ + +theorem iff_exists_smul_integral [IsReduced R] (inj : Function.Injective (algebraMap R A)) : + IsAlgebraic R z ↔ ∃ y ≠ (0 : R), IsIntegral R (y • z) := + ⟨(exists_integral_multiple · inj), fun ⟨_, hy, int⟩ ↦ + of_smul_isIntegral (by rwa [isNilpotent_iff_eq_zero]) int⟩ + +section trans + +variable (R) [NoZeroDivisors S] (inj : Function.Injective (algebraMap S A)) +include inj + +theorem restrictScalars_of_isIntegral [int : Algebra.IsIntegral R S] + {a : A} (h : IsAlgebraic S a) : IsAlgebraic R a := by + by_cases hRS : Function.Injective (algebraMap R S) + on_goal 2 => exact (Algebra.isAlgebraic_of_not_injective + fun h ↦ hRS <| .of_comp (IsScalarTower.algebraMap_eq R S A ▸ h)).1 _ + have := hRS.noZeroDivisors _ (map_zero _) (map_mul _) + have ⟨s, hs, int_s⟩ := h.exists_integral_multiple inj + cases subsingleton_or_nontrivial R + · have := Module.subsingleton R S + exact (is_transcendental_of_subsingleton _ _ h).elim + have ⟨r, hr, _, e⟩ := (int.1 s).isAlgebraic.exists_nonzero_dvd (mem_nonZeroDivisors_of_ne_zero hs) + refine .of_smul_isIntegral (y := r) (by rwa [isNilpotent_iff_eq_zero]) ?_ + rw [Algebra.smul_def, IsScalarTower.algebraMap_apply R S, + e, ← Algebra.smul_def, mul_comm, mul_smul] + exact isIntegral_trans _ (int_s.smul _) + +theorem restrictScalars [Algebra.IsAlgebraic R S] + {a : A} (h : IsAlgebraic S a) : IsAlgebraic R a := by + have ⟨p, hp, eval0⟩ := h + by_cases hRS : Function.Injective (algebraMap R S) + on_goal 2 => exact (Algebra.isAlgebraic_of_not_injective + fun h ↦ hRS <| .of_comp (IsScalarTower.algebraMap_eq R S A ▸ h)).1 _ + have := hRS.noZeroDivisors _ (map_zero _) (map_mul _) + classical + have ⟨r, hr, int⟩ := Algebra.IsAlgebraic.exists_integral_multiples hRS (p.support.image (coeff p)) + let p := (r • p).toSubring (integralClosure R S).toSubring fun s hs ↦ by + obtain ⟨n, hn, rfl⟩ := mem_coeffs_iff.mp hs + exact int _ (Finset.mem_image_of_mem _ <| support_smul _ _ hn) + have : IsAlgebraic (integralClosure R S) a := by + refine ⟨p, ?_, ?_⟩ + · have := NoZeroSMulDivisors.of_algebraMap_injective hRS + simpa only [← Polynomial.map_ne_zero_iff (f := Subring.subtype _) Subtype.val_injective, + p, map_toSubring, smul_ne_zero_iff] using And.intro hr hp + rw [← eval_map_algebraMap, Subalgebra.algebraMap_eq, ← map_map, ← Subalgebra.toSubring_subtype, + map_toSubring, eval_map_algebraMap, ← AlgHom.restrictScalars_apply R, + map_smul, AlgHom.restrictScalars_apply, eval0, smul_zero] + exact restrictScalars_of_isIntegral _ (by exact inj.comp Subtype.val_injective) this + +theorem _root_.IsIntegral.trans_isAlgebraic [alg : Algebra.IsAlgebraic R S] + {a : A} (h : IsIntegral S a) : IsAlgebraic R a := by + cases subsingleton_or_nontrivial A + · have := Algebra.IsAlgebraic.nontrivial R S + exact Subsingleton.elim a 0 ▸ isAlgebraic_zero + · have := Module.nontrivial S A + exact h.isAlgebraic.restrictScalars _ inj + +end trans + +variable [nzd : NoZeroDivisors R] {a b : S} (ha : IsAlgebraic R a) (hb : IsAlgebraic R b) +include ha +omit nzd + +protected lemma neg : IsAlgebraic R (-a) := + have ⟨p, h, eval0⟩ := ha + ⟨algEquivAevalNegX p, EmbeddingLike.map_ne_zero_iff.mpr h, by simpa [← comp_eq_aeval, aeval_comp]⟩ + +protected lemma smul (r : R) : IsAlgebraic R (r • a) := + have ⟨_, hp, eval0⟩ := ha + ⟨_, scaleRoots_ne_zero hp r, Algebra.smul_def r a ▸ scaleRoots_aeval_eq_zero eval0⟩ + +protected lemma nsmul (n : ℕ) : IsAlgebraic R (n • a) := + Nat.cast_smul_eq_nsmul R n a ▸ ha.smul _ + +protected lemma zsmul (n : ℤ) : IsAlgebraic R (n • a) := + Int.cast_smul_eq_zsmul R n a ▸ ha.smul _ + +include hb nzd + +protected lemma mul : IsAlgebraic R (a * b) := by + refine (em _).elim (fun h ↦ ?_) fun h ↦ (Algebra.isAlgebraic_of_not_injective h).1 _ + have ⟨ra, a0, int_a⟩ := ha.exists_integral_multiple h + have ⟨rb, b0, int_b⟩ := hb.exists_integral_multiple h + refine (IsAlgebraic.iff_exists_smul_integral h).mpr ⟨_, mul_ne_zero a0 b0, ?_⟩ + simp_rw [Algebra.smul_def, map_mul, mul_mul_mul_comm, ← Algebra.smul_def] + exact int_a.mul int_b + +protected lemma add : IsAlgebraic R (a + b) := by + refine (em _).elim (fun h ↦ ?_) fun h ↦ (Algebra.isAlgebraic_of_not_injective h).1 _ + have ⟨ra, a0, int_a⟩ := ha.exists_integral_multiple h + have ⟨rb, b0, int_b⟩ := hb.exists_integral_multiple h + refine (IsAlgebraic.iff_exists_smul_integral h).mpr ⟨_, mul_ne_zero b0 a0, ?_⟩ + rw [smul_add, mul_smul, mul_comm, mul_smul] + exact (int_a.smul _).add (int_b.smul _) + +protected lemma sub : IsAlgebraic R (a - b) := + sub_eq_add_neg a b ▸ ha.add hb.neg + +omit hb +protected lemma pow (n : ℕ) : IsAlgebraic R (a ^ n) := + have := ha.nontrivial + n.rec (pow_zero a ▸ isAlgebraic_one) fun _ h ↦ pow_succ a _ ▸ h.mul ha + +end IsAlgebraic + +namespace Algebra + +variable (R) [NoZeroDivisors S] (inj : Function.Injective (algebraMap S A)) +include inj + +/-- Transitivity of algebraicity for algebras over domains. -/ +theorem IsAlgebraic.trans' [Algebra.IsAlgebraic R S] [alg : Algebra.IsAlgebraic S A] : + Algebra.IsAlgebraic R A := + ⟨fun _ ↦ (alg.1 _).restrictScalars _ inj⟩ + +theorem IsIntegral.trans_isAlgebraic [Algebra.IsIntegral R S] [alg : Algebra.IsAlgebraic S A] : + Algebra.IsAlgebraic R A := + ⟨fun _ ↦ (alg.1 _).restrictScalars_of_isIntegral _ inj⟩ + +theorem IsAlgebraic.trans_isIntegral [Algebra.IsAlgebraic R S] [int : Algebra.IsIntegral S A] : + Algebra.IsAlgebraic R A := + ⟨fun _ ↦ (int.1 _).trans_isAlgebraic _ inj⟩ + +end Algebra + +variable (R S) +/-- If `R` is a domain and `S` is an arbitrary `R`-algebra, then the elements of `S` +that are algebraic over `R` form a subalgebra. -/ +def Subalgebra.algebraicClosure [IsDomain R] : Subalgebra R S where + carrier := {s | _root_.IsAlgebraic R s} + mul_mem' ha hb := ha.mul hb + add_mem' ha hb := ha.add hb + algebraMap_mem' := isAlgebraic_algebraMap + +theorem integralClosure_le_algebraicClosure [IsDomain R] : + integralClosure R S ≤ Subalgebra.algebraicClosure R S := + fun _ ↦ IsIntegral.isAlgebraic + +theorem Subalgebra.algebraicClosure_eq_integralClosure {K} [Field K] [Algebra K S] : + algebraicClosure K S = integralClosure K S := + SetLike.ext fun _ ↦ isAlgebraic_iff_isIntegral + +instance [IsDomain R] : Algebra.IsAlgebraic R (Subalgebra.algebraicClosure R S) := + (Subalgebra.isAlgebraic_iff _).mp fun _ ↦ id + +variable {R S} + +theorem Algebra.isAlgebraic_adjoin_iff [IsDomain R] {s : Set S} : + (adjoin R s).IsAlgebraic ↔ ∀ x ∈ s, IsAlgebraic R x := + Algebra.adjoin_le_iff (S := Subalgebra.algebraicClosure R S) + +theorem Algebra.isAlgebraic_adjoin_of_nonempty [NoZeroDivisors R] {s : Set S} (hs : s.Nonempty) : + (adjoin R s).IsAlgebraic ↔ ∀ x ∈ s, IsAlgebraic R x := + ⟨fun h x hx ↦ h _ (subset_adjoin hx), fun h ↦ + have ⟨x, hx⟩ := hs + have := (isDomain_iff_noZeroDivisors_and_nontrivial _).mpr ⟨‹_›, (h x hx).nontrivial⟩ + isAlgebraic_adjoin_iff.mpr h⟩ + +theorem Algebra.isAlgebraic_adjoin_singleton_iff [NoZeroDivisors R] {s : S} : + (adjoin R {s}).IsAlgebraic ↔ IsAlgebraic R s := + (isAlgebraic_adjoin_of_nonempty <| Set.singleton_nonempty s).trans forall_eq + +theorem IsAlgebraic.of_mul [NoZeroDivisors R] {y z : S} (hy : y ∈ nonZeroDivisors S) + (alg_y : IsAlgebraic R y) (alg_yz : IsAlgebraic R (y * z)) : IsAlgebraic R z := by + have ⟨t, ht, r, hr, eq⟩ := alg_y.exists_nonzero_eq_adjoin_mul hy + have := alg_yz.mul (Algebra.isAlgebraic_adjoin_singleton_iff.mpr alg_y _ ht) + rw [mul_right_comm, eq, ← Algebra.smul_def] at this + exact this.of_smul (mem_nonZeroDivisors_of_ne_zero hr) + +namespace Transcendental + +section + +variable {a : A} (ha : Transcendental R a) +include ha + +lemma extendScalars_of_isIntegral [NoZeroDivisors S] [Algebra.IsIntegral R S] + (inj : Function.Injective (algebraMap S A)) : Transcendental S a := by + contrapose ha + rw [Transcendental, not_not] at ha ⊢ + exact ha.restrictScalars_of_isIntegral _ inj + +lemma extendScalars [NoZeroDivisors S] [Algebra.IsAlgebraic R S] + (inj : Function.Injective (algebraMap S A)) : Transcendental S a := by + contrapose ha + rw [Transcendental, not_not] at ha ⊢ + exact ha.restrictScalars _ inj + +end + +variable {a : S} (ha : Transcendental R a) +include ha + +protected lemma integralClosure [NoZeroDivisors S] : + Transcendental (integralClosure R S) a := + ha.extendScalars_of_isIntegral Subtype.val_injective + +lemma subalgebraAlgebraicClosure [IsDomain R] [NoZeroDivisors S] : + Transcendental (Subalgebra.algebraicClosure R S) a := + ha.extendScalars Subtype.val_injective + +end Transcendental diff --git a/Mathlib/RingTheory/Algebraic/LinearIndependent.lean b/Mathlib/RingTheory/Algebraic/LinearIndependent.lean new file mode 100644 index 0000000000000..4104fb48d25b5 --- /dev/null +++ b/Mathlib/RingTheory/Algebraic/LinearIndependent.lean @@ -0,0 +1,50 @@ +/- +Copyright (c) 2019 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.LinearAlgebra.LinearIndependent +import Mathlib.RingTheory.Algebraic.Defs + +/-! +# Linear independence of transcendental elements + +## Main result + +* `Transcendental.linearIndependent_sub_inv`: let `x : E` transcendental over `F`, + then `{(x - a)⁻¹ | a : F}` is linearly independent over `F`. +-/ + +open Polynomial + +section + +/-- If `E / F` is a field extension, `x` is an element of `E` transcendental over `F`, +then `{(x - a)⁻¹ | a : F}` is linearly independent over `F`. -/ +theorem Transcendental.linearIndependent_sub_inv + {F E : Type*} [Field F] [Field E] [Algebra F E] {x : E} (H : Transcendental F x) : + LinearIndependent F fun a ↦ (x - algebraMap F E a)⁻¹ := by + classical + rw [transcendental_iff] at H + refine linearIndependent_iff'.2 fun s m hm i hi ↦ ?_ + have hnz (a : F) : x - algebraMap F E a ≠ 0 := fun h ↦ + X_sub_C_ne_zero a <| H (.X - .C a) (by simp [h]) + let b := s.prod fun j ↦ x - algebraMap F E j + have h1 : ∀ i ∈ s, m i • (b * (x - algebraMap F E i)⁻¹) = + m i • (s.erase i).prod fun j ↦ x - algebraMap F E j := fun i hi ↦ by + simp_rw [b, ← s.prod_erase_mul _ hi, mul_inv_cancel_right₀ (hnz i)] + replace hm := congr(b * $(hm)) + simp_rw [mul_zero, Finset.mul_sum, mul_smul_comm, Finset.sum_congr rfl h1] at hm + let p : Polynomial F := s.sum fun i ↦ .C (m i) * (s.erase i).prod fun j ↦ .X - .C j + replace hm := congr(Polynomial.aeval i $(H p (by simp_rw [← hm, p, map_sum, map_mul, map_prod, + map_sub, aeval_X, aeval_C, Algebra.smul_def]))) + have h2 : ∀ j ∈ s.erase i, m j * ((s.erase j).prod fun x ↦ i - x) = 0 := fun j hj ↦ by + have := Finset.mem_erase_of_ne_of_mem (Finset.ne_of_mem_erase hj).symm hi + simp_rw [← (s.erase j).prod_erase_mul _ this, sub_self, mul_zero] + simp_rw [map_zero, p, map_sum, map_mul, map_prod, map_sub, aeval_X, + aeval_C, Algebra.id.map_eq_self, ← s.sum_erase_add _ hi, + Finset.sum_eq_zero h2, zero_add] at hm + exact eq_zero_of_ne_zero_of_mul_right_eq_zero (Finset.prod_ne_zero_iff.2 fun j hj ↦ + sub_ne_zero.2 (Finset.ne_of_mem_erase hj).symm) hm + +end diff --git a/Mathlib/RingTheory/Algebraic/MvPolynomial.lean b/Mathlib/RingTheory/Algebraic/MvPolynomial.lean new file mode 100644 index 0000000000000..8ff2e80a728e9 --- /dev/null +++ b/Mathlib/RingTheory/Algebraic/MvPolynomial.lean @@ -0,0 +1,102 @@ +/- +Copyright (c) 2019 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.Algebra.MvPolynomial.Supported +import Mathlib.RingTheory.Adjoin.Polynomial +import Mathlib.RingTheory.Algebraic.Basic + +/-! +# Transcendental elements in `MvPolynomial` + +This file lists some results on some elements in `MvPolynomial σ R` being transcendental +over the base ring `R` and subrings `MvPolynomial.supported` of `MvPolynomial σ R`. +-/ + +universe u v w + +open Polynomial + +namespace MvPolynomial + +variable {σ : Type*} (R : Type*) [CommRing R] + +theorem transcendental_supported_polynomial_aeval_X {i : σ} {s : Set σ} (h : i ∉ s) + {f : R[X]} (hf : Transcendental R f) : + Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) := by + classical + rw [transcendental_iff_injective] at hf ⊢ + let g := MvPolynomial.mapAlgHom (R := R) (σ := s) (Polynomial.aeval (R := R) f) + replace hf : Function.Injective g := MvPolynomial.map_injective _ hf + let u := (Subalgebra.val _).comp + ((optionEquivRight R s).symm |>.trans + (renameEquiv R (Set.subtypeInsertEquivOption h).symm) |>.trans + (supportedEquivMvPolynomial _).symm).toAlgHom |>.comp + g |>.comp + ((optionEquivLeft R s).symm.trans (optionEquivRight R s)).toAlgHom + let v := ((Polynomial.aeval (R := supported R s) + (Polynomial.aeval (X i : MvPolynomial σ R) f)).restrictScalars R).comp + (Polynomial.mapAlgEquiv (supportedEquivMvPolynomial s).symm).toAlgHom + replace hf : Function.Injective u := by + simp only [AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, Subalgebra.coe_val, + AlgHom.coe_coe, AlgEquiv.coe_trans, Function.comp_assoc, u] + apply Subtype.val_injective.comp + simp only [EquivLike.comp_injective] + apply hf.comp + simp only [EquivLike.comp_injective, EquivLike.injective] + have h1 : Polynomial.aeval (X i : MvPolynomial σ R) = ((Subalgebra.val _).comp + (supportedEquivMvPolynomial _).symm.toAlgHom |>.comp + (Polynomial.aeval (X ⟨i, s.mem_insert i⟩ : MvPolynomial ↑(insert i s) R))) := by + ext1; simp + have h2 : u = v := by + simp only [u, v, g] + ext1 + · ext1 + simp [Set.subtypeInsertEquivOption, Subalgebra.algebraMap_eq] + · simp [Set.subtypeInsertEquivOption, h1] + simpa only [h2, v, AlgEquiv.toAlgHom_eq_coe, AlgHom.coe_comp, AlgHom.coe_coe, + EquivLike.injective_comp, AlgHom.coe_restrictScalars'] using hf + +theorem transcendental_polynomial_aeval_X (i : σ) {f : R[X]} (hf : Transcendental R f) : + Transcendental R (Polynomial.aeval (X i : MvPolynomial σ R) f) := by + have := transcendental_supported_polynomial_aeval_X R (Set.not_mem_empty i) hf + let g := (Algebra.botEquivOfInjective (MvPolynomial.C_injective σ R)).symm.trans + (Subalgebra.equivOfEq _ _ supported_empty).symm + rwa [Transcendental, ← isAlgebraic_ringHom_iff_of_comp_eq g (RingHom.id (MvPolynomial σ R)) + Function.injective_id (by ext1; rfl), RingHom.id_apply, ← Transcendental] + +theorem transcendental_polynomial_aeval_X_iff (i : σ) {f : R[X]} : + Transcendental R (Polynomial.aeval (X i : MvPolynomial σ R) f) ↔ Transcendental R f := by + refine ⟨?_, transcendental_polynomial_aeval_X R i⟩ + simp_rw [Transcendental, not_imp_not] + exact fun h ↦ h.algHom _ + +theorem transcendental_supported_polynomial_aeval_X_iff + [Nontrivial R] {i : σ} {s : Set σ} {f : R[X]} : + Transcendental (supported R s) (Polynomial.aeval (X i : MvPolynomial σ R) f) ↔ + i ∉ s ∧ Transcendental R f := by + refine ⟨fun h ↦ ⟨?_, ?_⟩, fun ⟨h, hf⟩ ↦ transcendental_supported_polynomial_aeval_X R h hf⟩ + · rw [Transcendental] at h + contrapose! h + refine isAlgebraic_algebraMap (⟨Polynomial.aeval (X i) f, ?_⟩ : supported R s) + exact Algebra.adjoin_mono (Set.singleton_subset_iff.2 (Set.mem_image_of_mem _ h)) + (Polynomial.aeval_mem_adjoin_singleton _ _) + · rw [← transcendental_polynomial_aeval_X_iff R i] + refine h.restrictScalars fun _ _ heq ↦ MvPolynomial.C_injective σ R ?_ + simp_rw [← MvPolynomial.algebraMap_eq] + exact congr($(heq).1) + +theorem transcendental_supported_X {i : σ} {s : Set σ} (h : i ∉ s) : + Transcendental (supported R s) (X i : MvPolynomial σ R) := by + simpa using transcendental_supported_polynomial_aeval_X R h (Polynomial.transcendental_X R) + +theorem transcendental_X (i : σ) : Transcendental R (X i : MvPolynomial σ R) := by + simpa using transcendental_polynomial_aeval_X R i (Polynomial.transcendental_X R) + +theorem transcendental_supported_X_iff [Nontrivial R] {i : σ} {s : Set σ} : + Transcendental (supported R s) (X i : MvPolynomial σ R) ↔ i ∉ s := by + simpa [Polynomial.transcendental_X] using + transcendental_supported_polynomial_aeval_X_iff R (i := i) (s := s) (f := Polynomial.X) + +end MvPolynomial diff --git a/Mathlib/RingTheory/Algebraic/Pi.lean b/Mathlib/RingTheory/Algebraic/Pi.lean new file mode 100644 index 0000000000000..c09c0c2414404 --- /dev/null +++ b/Mathlib/RingTheory/Algebraic/Pi.lean @@ -0,0 +1,90 @@ +/- +Copyright (c) 2019 Johan Commelin. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Johan Commelin +-/ +import Mathlib.Algebra.Polynomial.AlgebraMap + +/-! +# Algebraic functions + +This file defines algebraic functions as the image of the `algebraMap R[X] (R → S)`. +-/ + +assert_not_exists IsIntegralClosure +assert_not_exists LinearIndependent +assert_not_exists LocalRing +assert_not_exists MvPolynomial + +open Polynomial + +section Pi + +variable (R S T : Type*) + +/-- This is not an instance as it forms a diamond with `Pi.instSMul`. + +See the `instance_diamonds` test for details. -/ +def Polynomial.hasSMulPi [Semiring R] [SMul R S] : SMul R[X] (R → S) := + ⟨fun p f x => eval x p • f x⟩ + +/-- This is not an instance as it forms a diamond with `Pi.instSMul`. + +See the `instance_diamonds` test for details. -/ +noncomputable def Polynomial.hasSMulPi' [CommSemiring R] [Semiring S] [Algebra R S] + [SMul S T] : SMul R[X] (S → T) := + ⟨fun p f x => aeval x p • f x⟩ + +attribute [local instance] Polynomial.hasSMulPi Polynomial.hasSMulPi' + +@[simp] +theorem polynomial_smul_apply [Semiring R] [SMul R S] (p : R[X]) (f : R → S) (x : R) : + (p • f) x = eval x p • f x := + rfl + +@[simp] +theorem polynomial_smul_apply' [CommSemiring R] [Semiring S] [Algebra R S] [SMul S T] + (p : R[X]) (f : S → T) (x : S) : (p • f) x = aeval x p • f x := + rfl + +variable [CommSemiring R] [CommSemiring S] [CommSemiring T] [Algebra R S] [Algebra S T] + +-- Porting note: the proofs in this definition used `funext` in term-mode, but I was not able +-- to get them to work anymore. +/-- This is not an instance for the same reasons as `Polynomial.hasSMulPi'`. -/ +noncomputable def Polynomial.algebraPi : Algebra R[X] (S → T) := + { Polynomial.hasSMulPi' R S T with + toFun := fun p z => algebraMap S T (aeval z p) + map_one' := by + funext z + simp only [Polynomial.aeval_one, Pi.one_apply, map_one] + map_mul' := fun f g => by + funext z + simp only [Pi.mul_apply, map_mul] + map_zero' := by + funext z + simp only [Polynomial.aeval_zero, Pi.zero_apply, map_zero] + map_add' := fun f g => by + funext z + simp only [Polynomial.aeval_add, Pi.add_apply, map_add] + commutes' := fun p f => by + funext z + exact mul_comm _ _ + smul_def' := fun p f => by + funext z + simp only [polynomial_smul_apply', Algebra.algebraMap_eq_smul_one, RingHom.coe_mk, + MonoidHom.coe_mk, OneHom.coe_mk, Pi.mul_apply, Algebra.smul_mul_assoc, one_mul] } + +attribute [local instance] Polynomial.algebraPi + +@[simp] +theorem Polynomial.algebraMap_pi_eq_aeval : + (algebraMap R[X] (S → T) : R[X] → S → T) = fun p z => algebraMap _ _ (aeval z p) := + rfl + +@[simp] +theorem Polynomial.algebraMap_pi_self_eq_eval : + (algebraMap R[X] (R → R) : R[X] → R → R) = fun p z => eval z p := + rfl + +end Pi diff --git a/Mathlib/RingTheory/AlgebraicIndependent.lean b/Mathlib/RingTheory/AlgebraicIndependent.lean deleted file mode 100644 index a82ccfeeb3732..0000000000000 --- a/Mathlib/RingTheory/AlgebraicIndependent.lean +++ /dev/null @@ -1,804 +0,0 @@ -/- -Copyright (c) 2021 Chris Hughes. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Hughes --/ -import Mathlib.Algebra.MvPolynomial.Monad -import Mathlib.Data.Fin.Tuple.Reflection -import Mathlib.FieldTheory.Adjoin -import Mathlib.FieldTheory.MvRatFunc.Rank -import Mathlib.RingTheory.Algebraic.Cardinality -import Mathlib.RingTheory.MvPolynomial.Basic - -/-! -# Algebraic Independence - -This file defines algebraic independence of a family of element of an `R` algebra. - -## Main definitions - -* `AlgebraicIndependent` - `AlgebraicIndependent R x` states the family of elements `x` - is algebraically independent over `R`, meaning that the canonical map out of the multivariable - polynomial ring is injective. - -* `AlgebraicIndependent.aevalEquiv` - The canonical isomorphism from the polynomial ring to the - subalgebra generated by an algebraic independent family. - -* `AlgebraicIndependent.repr` - The canonical map from the subalgebra generated by an - algebraic independent family into the polynomial ring. It is the inverse of - `AlgebraicIndependent.aevalEquiv`. - -* `AlgebraicIndependent.aevalEquivField` - The canonical isomorphism from the rational function - field ring to the intermediate field generated by an algebraic independent family. - -* `AlgebraicIndependent.reprField` - The canonical map from the intermediate field generated by an - algebraic independent family into the rational function field. It is the inverse of - `AlgebraicIndependent.aevalEquivField`. - -* `IsTranscendenceBasis R x` - a family `x` is a transcendence basis over `R` if it is a maximal - algebraically independent subset. - -## References - -* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) - -## TODO -Define the transcendence degree and show it is independent of the choice of a -transcendence basis. - -## Tags -transcendence basis, transcendence degree, transcendence - --/ - - -noncomputable section - -open Function Set Subalgebra MvPolynomial Algebra - -open scoped Classical - -universe u v w - -variable {ι : Type*} {ι' : Type*} (R : Type*) {K : Type*} -variable {A : Type*} {A' : Type*} -variable (x : ι → A) -variable [CommRing R] [CommRing A] [CommRing A'] [Algebra R A] [Algebra R A'] - -/-- `AlgebraicIndependent R x` states the family of elements `x` - is algebraically independent over `R`, meaning that the canonical - map out of the multivariable polynomial ring is injective. -/ -def AlgebraicIndependent : Prop := - Injective (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A) - -variable {R} {x} - -theorem algebraicIndependent_iff_ker_eq_bot : - AlgebraicIndependent R x ↔ - RingHom.ker (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A).toRingHom = ⊥ := - RingHom.injective_iff_ker_eq_bot _ - -theorem algebraicIndependent_iff : - AlgebraicIndependent R x ↔ - ∀ p : MvPolynomial ι R, MvPolynomial.aeval (x : ι → A) p = 0 → p = 0 := - injective_iff_map_eq_zero _ - -theorem AlgebraicIndependent.eq_zero_of_aeval_eq_zero (h : AlgebraicIndependent R x) : - ∀ p : MvPolynomial ι R, MvPolynomial.aeval (x : ι → A) p = 0 → p = 0 := - algebraicIndependent_iff.1 h - -theorem algebraicIndependent_iff_injective_aeval : - AlgebraicIndependent R x ↔ Injective (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A) := - Iff.rfl - -@[simp] -theorem algebraicIndependent_empty_type_iff [IsEmpty ι] : - AlgebraicIndependent R x ↔ Injective (algebraMap R A) := by - rw [algebraicIndependent_iff_injective_aeval, MvPolynomial.aeval_injective_iff_of_isEmpty] - -/-- A one-element family `x` is algebraically independent if and only if -its element is transcendental. -/ -@[simp] -theorem algebraicIndependent_unique_type_iff [Unique ι] : - AlgebraicIndependent R x ↔ Transcendental R (x default) := by - rw [transcendental_iff_injective, algebraicIndependent_iff_injective_aeval] - let i := (renameEquiv R (Equiv.equivPUnit.{_, 1} ι)).trans (pUnitAlgEquiv R) - have key : aeval (R := R) x = (Polynomial.aeval (R := R) (x default)).comp i := by - ext y - simp [i, Subsingleton.elim y default] - simp [key] - -/-- The one-element family `![x]` is algebraically independent if and only if -`x` is transcendental. -/ -theorem algebraicIndependent_iff_transcendental {x : A} : - AlgebraicIndependent R ![x] ↔ Transcendental R x := by - simp - -namespace AlgebraicIndependent - -theorem of_comp (f : A →ₐ[R] A') (hfv : AlgebraicIndependent R (f ∘ x)) : - AlgebraicIndependent R x := by - have : aeval (f ∘ x) = f.comp (aeval x) := by ext; simp - rw [AlgebraicIndependent, this, AlgHom.coe_comp] at hfv - exact hfv.of_comp - -variable (hx : AlgebraicIndependent R x) -include hx - -theorem algebraMap_injective : Injective (algebraMap R A) := by - simpa [Function.comp_def] using - (Injective.of_comp_iff (algebraicIndependent_iff_injective_aeval.1 hx) MvPolynomial.C).2 - (MvPolynomial.C_injective _ _) - -theorem linearIndependent : LinearIndependent R x := by - rw [linearIndependent_iff_injective_linearCombination] - have : Finsupp.linearCombination R x = - (MvPolynomial.aeval x).toLinearMap.comp (Finsupp.linearCombination R X) := by - ext - simp - rw [this] - refine hx.comp ?_ - rw [← linearIndependent_iff_injective_linearCombination] - exact linearIndependent_X _ _ - -protected theorem injective [Nontrivial R] : Injective x := - hx.linearIndependent.injective - -theorem ne_zero [Nontrivial R] (i : ι) : x i ≠ 0 := - hx.linearIndependent.ne_zero i - -theorem comp (f : ι' → ι) (hf : Function.Injective f) : AlgebraicIndependent R (x ∘ f) := by - intro p q - simpa [aeval_rename, (rename_injective f hf).eq_iff] using @hx (rename f p) (rename f q) - -theorem coe_range : AlgebraicIndependent R ((↑) : range x → A) := by - simpa using hx.comp _ (rangeSplitting_injective x) - -theorem map {f : A →ₐ[R] A'} (hf_inj : Set.InjOn f (adjoin R (range x))) : - AlgebraicIndependent R (f ∘ x) := by - have : aeval (f ∘ x) = f.comp (aeval x) := by ext; simp - have h : ∀ p : MvPolynomial ι R, aeval x p ∈ (@aeval R _ _ _ _ _ ((↑) : range x → A)).range := by - intro p - rw [AlgHom.mem_range] - refine ⟨MvPolynomial.rename (codRestrict x (range x) mem_range_self) p, ?_⟩ - simp [Function.comp_def, aeval_rename] - intro x y hxy - rw [this] at hxy - rw [adjoin_eq_range] at hf_inj - exact hx (hf_inj (h x) (h y) hxy) - -theorem map' {f : A →ₐ[R] A'} (hf_inj : Injective f) : AlgebraicIndependent R (f ∘ x) := - hx.map hf_inj.injOn - -/-- If a family `x` is algebraically independent, then any of its element is transcendental. -/ -theorem transcendental (i : ι) : Transcendental R (x i) := by - have := hx.comp ![i] (Function.injective_of_subsingleton _) - have : AlgebraicIndependent R ![x i] := by rwa [← FinVec.map_eq] at this - rwa [← algebraicIndependent_iff_transcendental] - -/-- If `x = {x_i : A | i : ι}` and `f = {f_i : MvPolynomial ι R | i : ι}` are algebraically -independent over `R`, then `{f_i(x) | i : ι}` is also algebraically independent over `R`. -For the partial converse, see `AlgebraicIndependent.of_aeval`. -/ -theorem aeval_of_algebraicIndependent - {f : ι → MvPolynomial ι R} (hf : AlgebraicIndependent R f) : - AlgebraicIndependent R fun i ↦ aeval x (f i) := by - rw [algebraicIndependent_iff] at hx hf ⊢ - intro p hp - exact hf _ (hx _ (by rwa [← aeval_comp_bind₁, AlgHom.comp_apply] at hp)) - -omit hx in -/-- If `{f_i(x) | i : ι}` is algebraically independent over `R`, then -`{f_i : MvPolynomial ι R | i : ι}` is also algebraically independent over `R`. -In fact, the `x = {x_i : A | i : ι}` is also transcendental over `R` provided that `R` -is a field and `ι` is finite; the proof needs transcendence degree. -/ -theorem of_aeval {f : ι → MvPolynomial ι R} - (H : AlgebraicIndependent R fun i ↦ aeval x (f i)) : - AlgebraicIndependent R f := by - rw [algebraicIndependent_iff] at H ⊢ - intro p hp - exact H p (by rw [← aeval_comp_bind₁, AlgHom.comp_apply, bind₁, hp, map_zero]) - -/-- If `A/R` is algebraic, then all algebraically independent families are empty. -/ -theorem isEmpty_of_isAlgebraic [Algebra.IsAlgebraic R A] : IsEmpty ι := by - rcases isEmpty_or_nonempty ι with h | ⟨⟨i⟩⟩ - · exact h - exact False.elim (hx.transcendental i (Algebra.IsAlgebraic.isAlgebraic _)) - -end AlgebraicIndependent - -theorem MvPolynomial.algebraicIndependent_X (σ R : Type*) [CommRing R] : - AlgebraicIndependent R (X (R := R) (σ := σ)) := by - rw [AlgebraicIndependent, aeval_X_left] - exact injective_id - -open AlgebraicIndependent - -theorem AlgHom.algebraicIndependent_iff (f : A →ₐ[R] A') (hf : Injective f) : - AlgebraicIndependent R (f ∘ x) ↔ AlgebraicIndependent R x := - ⟨fun h => h.of_comp f, fun h => h.map hf.injOn⟩ - -@[nontriviality] -theorem algebraicIndependent_of_subsingleton [Subsingleton R] : AlgebraicIndependent R x := - algebraicIndependent_iff.2 fun _ _ => Subsingleton.elim _ _ - -theorem algebraicIndependent_equiv (e : ι ≃ ι') {f : ι' → A} : - AlgebraicIndependent R (f ∘ e) ↔ AlgebraicIndependent R f := - ⟨fun h => Function.comp_id f ▸ e.self_comp_symm ▸ h.comp _ e.symm.injective, - fun h => h.comp _ e.injective⟩ - -theorem algebraicIndependent_equiv' (e : ι ≃ ι') {f : ι' → A} {g : ι → A} (h : f ∘ e = g) : - AlgebraicIndependent R g ↔ AlgebraicIndependent R f := - h ▸ algebraicIndependent_equiv e - -theorem algebraicIndependent_subtype_range {ι} {f : ι → A} (hf : Injective f) : - AlgebraicIndependent R ((↑) : range f → A) ↔ AlgebraicIndependent R f := - Iff.symm <| algebraicIndependent_equiv' (Equiv.ofInjective f hf) rfl - -alias ⟨AlgebraicIndependent.of_subtype_range, _⟩ := algebraicIndependent_subtype_range - -theorem algebraicIndependent_image {ι} {s : Set ι} {f : ι → A} (hf : Set.InjOn f s) : - (AlgebraicIndependent R fun x : s => f x) ↔ AlgebraicIndependent R fun x : f '' s => (x : A) := - algebraicIndependent_equiv' (Equiv.Set.imageOfInjOn _ _ hf) rfl - -theorem algebraicIndependent_adjoin (hs : AlgebraicIndependent R x) : - @AlgebraicIndependent ι R (adjoin R (range x)) - (fun i : ι => ⟨x i, subset_adjoin (mem_range_self i)⟩) _ _ _ := - AlgebraicIndependent.of_comp (adjoin R (range x)).val hs - -/-- A set of algebraically independent elements in an algebra `A` over a ring `K` is also -algebraically independent over a subring `R` of `K`. -/ -theorem AlgebraicIndependent.restrictScalars {K : Type*} [CommRing K] [Algebra R K] [Algebra K A] - [IsScalarTower R K A] (hinj : Function.Injective (algebraMap R K)) - (ai : AlgebraicIndependent K x) : AlgebraicIndependent R x := by - have : (aeval x : MvPolynomial ι K →ₐ[K] A).toRingHom.comp (MvPolynomial.map (algebraMap R K)) = - (aeval x : MvPolynomial ι R →ₐ[R] A).toRingHom := by - ext <;> simp [algebraMap_eq_smul_one] - show Injective (aeval x).toRingHom - rw [← this, RingHom.coe_comp] - exact Injective.comp ai (MvPolynomial.map_injective _ hinj) - -section RingHom - -variable {S B FRS FAB : Type*} [CommRing S] [CommRing B] [Algebra S B] - -section - -variable [FunLike FRS R S] [RingHomClass FRS R S] [FunLike FAB A B] [RingHomClass FAB A B] - (f : FRS) (g : FAB) - -theorem AlgebraicIndependent.of_ringHom_of_comp_eq (H : AlgebraicIndependent S (g ∘ x)) - (hf : Function.Injective f) - (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : - AlgebraicIndependent R x := by - rw [algebraicIndependent_iff] at H ⊢ - intro p hp - have := H (p.map f) <| by - have : (g : A →+* B) _ = _ := congr(g $hp) - rwa [map_zero, map_aeval, ← h, ← eval₂Hom_map_hom, ← aeval_eq_eval₂Hom] at this - exact map_injective f hf (by rwa [map_zero]) - -theorem AlgebraicIndependent.ringHom_of_comp_eq (H : AlgebraicIndependent R x) - (hf : Function.Surjective f) (hg : Function.Injective g) - (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : - AlgebraicIndependent S (g ∘ x) := by - rw [algebraicIndependent_iff] at H ⊢ - intro p hp - obtain ⟨q, rfl⟩ := map_surjective f hf p - rw [H q (hg (by rwa [map_zero, ← RingHom.coe_coe g, map_aeval, ← h, ← eval₂Hom_map_hom, - ← aeval_eq_eval₂Hom])), map_zero] - -end - -section - -variable [EquivLike FRS R S] [RingEquivClass FRS R S] [FunLike FAB A B] [RingHomClass FAB A B] - (f : FRS) (g : FAB) - -theorem algebraicIndependent_ringHom_iff_of_comp_eq - (hg : Function.Injective g) - (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : - AlgebraicIndependent S (g ∘ x) ↔ AlgebraicIndependent R x := - ⟨fun H ↦ H.of_ringHom_of_comp_eq f g (EquivLike.injective f) h, - fun H ↦ H.ringHom_of_comp_eq f g (EquivLike.surjective f) hg h⟩ - -end - -end RingHom - -/-- Every finite subset of an algebraically independent set is algebraically independent. -/ -theorem algebraicIndependent_finset_map_embedding_subtype (s : Set A) - (li : AlgebraicIndependent R ((↑) : s → A)) (t : Finset s) : - AlgebraicIndependent R ((↑) : Finset.map (Embedding.subtype s) t → A) := by - let f : t.map (Embedding.subtype s) → s := fun x => - ⟨x.1, by - obtain ⟨x, h⟩ := x - rw [Finset.mem_map] at h - obtain ⟨a, _, rfl⟩ := h - simp only [Subtype.coe_prop, Embedding.coe_subtype]⟩ - convert AlgebraicIndependent.comp li f _ - rintro ⟨x, hx⟩ ⟨y, hy⟩ - rw [Finset.mem_map] at hx hy - obtain ⟨a, _, rfl⟩ := hx - obtain ⟨b, _, rfl⟩ := hy - simp only [f, imp_self, Subtype.mk_eq_mk] - -/-- If every finite set of algebraically independent element has cardinality at most `n`, -then the same is true for arbitrary sets of algebraically independent elements. -/ -theorem algebraicIndependent_bounded_of_finset_algebraicIndependent_bounded {n : ℕ} - (H : ∀ s : Finset A, (AlgebraicIndependent R fun i : s => (i : A)) → s.card ≤ n) : - ∀ s : Set A, AlgebraicIndependent R ((↑) : s → A) → Cardinal.mk s ≤ n := by - intro s li - apply Cardinal.card_le_of - intro t - rw [← Finset.card_map (Embedding.subtype s)] - apply H - apply algebraicIndependent_finset_map_embedding_subtype _ li - -section Subtype - -theorem AlgebraicIndependent.restrict_of_comp_subtype {s : Set ι} - (hs : AlgebraicIndependent R (x ∘ (↑) : s → A)) : AlgebraicIndependent R (s.restrict x) := - hs - -variable (R A) - -theorem algebraicIndependent_empty_iff : - AlgebraicIndependent R ((↑) : (∅ : Set A) → A) ↔ Injective (algebraMap R A) := by simp - -variable {R A} - -theorem AlgebraicIndependent.mono {t s : Set A} (h : t ⊆ s) - (hx : AlgebraicIndependent R ((↑) : s → A)) : AlgebraicIndependent R ((↑) : t → A) := by - simpa [Function.comp] using hx.comp (inclusion h) (inclusion_injective h) - -end Subtype - -theorem AlgebraicIndependent.to_subtype_range {ι} {f : ι → A} (hf : AlgebraicIndependent R f) : - AlgebraicIndependent R ((↑) : range f → A) := by - nontriviality R - rwa [algebraicIndependent_subtype_range hf.injective] - -theorem AlgebraicIndependent.to_subtype_range' {ι} {f : ι → A} (hf : AlgebraicIndependent R f) {t} - (ht : range f = t) : AlgebraicIndependent R ((↑) : t → A) := - ht ▸ hf.to_subtype_range - -theorem algebraicIndependent_comp_subtype {s : Set ι} : - AlgebraicIndependent R (x ∘ (↑) : s → A) ↔ - ∀ p ∈ MvPolynomial.supported R s, aeval x p = 0 → p = 0 := by - have : (aeval (x ∘ (↑) : s → A) : _ →ₐ[R] _) = (aeval x).comp (rename (↑)) := by ext; simp - have : ∀ p : MvPolynomial s R, rename ((↑) : s → ι) p = 0 ↔ p = 0 := - (injective_iff_map_eq_zero' (rename ((↑) : s → ι) : MvPolynomial s R →ₐ[R] _).toRingHom).1 - (rename_injective _ Subtype.val_injective) - simp [algebraicIndependent_iff, supported_eq_range_rename, *] - -theorem algebraicIndependent_subtype {s : Set A} : - AlgebraicIndependent R ((↑) : s → A) ↔ - ∀ p : MvPolynomial A R, p ∈ MvPolynomial.supported R s → aeval id p = 0 → p = 0 := by - apply @algebraicIndependent_comp_subtype _ _ _ id - -theorem algebraicIndependent_of_finite (s : Set 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) - -theorem AlgebraicIndependent.image_of_comp {ι ι'} (s : Set ι) (f : ι → ι') (g : ι' → A) - (hs : AlgebraicIndependent R fun x : s => g (f x)) : - AlgebraicIndependent R fun x : f '' s => g x := by - nontriviality R - have : InjOn f s := injOn_iff_injective.2 hs.injective.of_comp - exact (algebraicIndependent_equiv' (Equiv.Set.imageOfInjOn f s this) rfl).1 hs - -theorem AlgebraicIndependent.image {ι} {s : Set ι} {f : ι → A} - (hs : AlgebraicIndependent R fun x : s => f x) : - AlgebraicIndependent R fun x : f '' s => (x : A) := by - convert AlgebraicIndependent.image_of_comp s f id hs - -theorem algebraicIndependent_iUnion_of_directed {η : Type*} [Nonempty η] {s : η → Set A} - (hs : Directed (· ⊆ ·) s) (h : ∀ i, AlgebraicIndependent R ((↑) : s i → A)) : - AlgebraicIndependent R ((↑) : (⋃ i, s i) → A) := by - refine algebraicIndependent_of_finite (⋃ i, s i) fun t ht ft => ?_ - rcases finite_subset_iUnion ft ht with ⟨I, fi, hI⟩ - rcases hs.finset_le fi.toFinset with ⟨i, hi⟩ - exact (h i).mono (Subset.trans hI <| iUnion₂_subset fun j hj => hi j (fi.mem_toFinset.2 hj)) - -theorem algebraicIndependent_sUnion_of_directed {s : Set (Set A)} (hsn : s.Nonempty) - (hs : DirectedOn (· ⊆ ·) s) (h : ∀ a ∈ s, AlgebraicIndependent R ((↑) : a → A)) : - AlgebraicIndependent R ((↑) : ⋃₀ s → A) := by - letI : Nonempty s := Nonempty.to_subtype hsn - rw [sUnion_eq_iUnion] - exact algebraicIndependent_iUnion_of_directed hs.directed_val (by simpa using h) - -theorem exists_maximal_algebraicIndependent (s t : Set A) (hst : s ⊆ t) - (hs : AlgebraicIndependent R ((↑) : s → A)) : ∃ u, s ⊆ u ∧ - Maximal (fun (x : Set A) ↦ AlgebraicIndependent R ((↑) : x → A) ∧ x ⊆ t) u := by - refine zorn_subset_nonempty { u : Set A | AlgebraicIndependent R ((↑) : u → A) ∧ u ⊆ t} - (fun c hc chainc hcn ↦ ⟨⋃₀ c, ⟨?_, ?_⟩, fun _ ↦ subset_sUnion_of_mem⟩) s ⟨hs, hst⟩ - · exact algebraicIndependent_sUnion_of_directed hcn chainc.directedOn (fun x hxc ↦ (hc hxc).1) - exact fun x ⟨w, hyc, hwy⟩ ↦ (hc hyc).2 hwy - -namespace AlgebraicIndependent - -section repr - -variable (hx : AlgebraicIndependent R x) -include hx - -/-- Canonical isomorphism between polynomials and the subalgebra generated by - algebraically independent elements. -/ -@[simps! apply_coe] -def aevalEquiv : MvPolynomial ι R ≃ₐ[R] Algebra.adjoin R (range x) := - (AlgEquiv.ofInjective (aeval x) (algebraicIndependent_iff_injective_aeval.1 hx)).trans - (Subalgebra.equivOfEq _ _ (Algebra.adjoin_range_eq_range_aeval R x).symm) - ---@[simp] Porting note: removing simp because the linter complains about deterministic timeout -theorem algebraMap_aevalEquiv (p : MvPolynomial ι R) : - algebraMap (Algebra.adjoin R (range x)) A (hx.aevalEquiv p) = aeval x p := - rfl - -/-- The canonical map from the subalgebra generated by an algebraic independent family - into the polynomial ring. -/ -def repr : Algebra.adjoin R (range x) →ₐ[R] MvPolynomial ι R := - hx.aevalEquiv.symm - -@[simp] -theorem aeval_repr (p) : aeval x (hx.repr p) = p := - Subtype.ext_iff.1 (AlgEquiv.apply_symm_apply hx.aevalEquiv p) - -theorem aeval_comp_repr : (aeval x).comp hx.repr = Subalgebra.val _ := - AlgHom.ext <| hx.aeval_repr - -theorem repr_ker : RingHom.ker (hx.repr : adjoin R (range x) →+* MvPolynomial ι R) = ⊥ := - (RingHom.injective_iff_ker_eq_bot _).1 (AlgEquiv.injective _) - -end repr - -section reprField - -variable {F E : Type*} {x : ι → E} [Field F] [Field E] [Algebra F E] (hx : AlgebraicIndependent F x) -include hx - -/-- Canonical isomorphism between rational function field and the - intermediate field generated by algebraically independent elements. -/ -def aevalEquivField : - FractionRing (MvPolynomial ι F) ≃ₐ[F] ↥(IntermediateField.adjoin F (range x)) := - let i := IsFractionRing.liftAlgHom (K := FractionRing (MvPolynomial ι F)) - (algebraicIndependent_iff_injective_aeval.2 hx) - (show _ ≃ₐ[F] i.fieldRange from AlgEquiv.ofInjectiveField i).trans <| - IntermediateField.equivOfEq <| - IsFractionRing.algHom_fieldRange_eq_of_comp_eq_of_range_eq (g := aeval x) (f := i) - (by ext <;> simp [i]) (Algebra.adjoin_range_eq_range_aeval F x).symm - -@[simp] -theorem aevalEquivField_apply_coe (a : FractionRing (MvPolynomial ι F)) : - hx.aevalEquivField a = - IsFractionRing.lift (algebraicIndependent_iff_injective_aeval.2 hx) a := rfl - -theorem aevalEquivField_algebraMap_apply_coe (a : MvPolynomial ι F) : - hx.aevalEquivField (algebraMap _ _ a) = aeval x a := by - simp - -/-- The canonical map from the intermediate field generated by an algebraic independent family - into the rational function field. -/ -def reprField : IntermediateField.adjoin F (range x) →ₐ[F] FractionRing (MvPolynomial ι F) := - hx.aevalEquivField.symm - -@[simp] -theorem lift_reprField (p) : - IsFractionRing.lift (algebraicIndependent_iff_injective_aeval.2 hx) (hx.reprField p) = p := - Subtype.ext_iff.1 (AlgEquiv.apply_symm_apply hx.aevalEquivField p) - -theorem liftAlgHom_comp_reprField : - (IsFractionRing.liftAlgHom (algebraicIndependent_iff_injective_aeval.2 hx)).comp hx.reprField = - IntermediateField.val _ := - AlgHom.ext <| hx.lift_reprField - -end reprField - -end AlgebraicIndependent - --- TODO - make this an `AlgEquiv` -/-- The isomorphism between `MvPolynomial (Option ι) R` and the polynomial ring over -the algebra generated by an algebraically independent family. -/ -def AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin (hx : AlgebraicIndependent R x) : - MvPolynomial (Option ι) R ≃+* Polynomial (adjoin R (Set.range x)) := - (MvPolynomial.optionEquivLeft _ _).toRingEquiv.trans - (Polynomial.mapEquiv hx.aevalEquiv.toRingEquiv) - -@[simp] -theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply - (hx : AlgebraicIndependent R x) (y) : - hx.mvPolynomialOptionEquivPolynomialAdjoin y = - Polynomial.map (hx.aevalEquiv : MvPolynomial ι R →+* adjoin R (range x)) - (aeval (fun o : Option ι => o.elim Polynomial.X fun s : ι => Polynomial.C (X s)) y) := - rfl - -/-- `simp`-normal form of `mvPolynomialOptionEquivPolynomialAdjoin_C` -/ -@[simp] -theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_C' - (hx : AlgebraicIndependent R x) (r) : - Polynomial.C (hx.aevalEquiv (C r)) = Polynomial.C (algebraMap _ _ r) := by - congr - apply_fun Subtype.val using Subtype.val_injective - simp - -theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_C - (hx : AlgebraicIndependent R x) (r) : - hx.mvPolynomialOptionEquivPolynomialAdjoin (C r) = Polynomial.C (algebraMap _ _ r) := by - simp - -theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_X_none - (hx : AlgebraicIndependent R x) : - hx.mvPolynomialOptionEquivPolynomialAdjoin (X none) = Polynomial.X := by - rw [AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply, aeval_X, Option.elim, - Polynomial.map_X] - -theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_X_some - (hx : AlgebraicIndependent R x) (i) : - hx.mvPolynomialOptionEquivPolynomialAdjoin (X (some i)) = - Polynomial.C (hx.aevalEquiv (X i)) := by - rw [AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply, aeval_X, Option.elim, - Polynomial.map_C, RingHom.coe_coe] - -theorem AlgebraicIndependent.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin - (hx : AlgebraicIndependent R x) (a : A) : - RingHom.comp - (↑(Polynomial.aeval a : Polynomial (adjoin R (Set.range x)) →ₐ[_] A) : - Polynomial (adjoin R (Set.range x)) →+* A) - hx.mvPolynomialOptionEquivPolynomialAdjoin.toRingHom = - ↑(MvPolynomial.aeval fun o : Option ι => o.elim a x : MvPolynomial (Option ι) R →ₐ[R] A) := by - refine MvPolynomial.ringHom_ext ?_ ?_ <;> - simp only [RingHom.comp_apply, RingEquiv.toRingHom_eq_coe, RingEquiv.coe_toRingHom, - AlgHom.coe_toRingHom, AlgHom.coe_toRingHom] - · intro r - rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_C, aeval_C, Polynomial.aeval_C, - IsScalarTower.algebraMap_apply R (adjoin R (range x)) A] - · rintro (⟨⟩ | ⟨i⟩) - · rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_X_none, aeval_X, Polynomial.aeval_X, - Option.elim] - · rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_X_some, Polynomial.aeval_C, - hx.algebraMap_aevalEquiv, aeval_X, aeval_X, Option.elim] - -theorem AlgebraicIndependent.option_iff (hx : AlgebraicIndependent R x) (a : A) : - (AlgebraicIndependent R fun o : Option ι => o.elim a x) ↔ - Transcendental (adjoin R (Set.range x)) a := by - rw [algebraicIndependent_iff_injective_aeval, transcendental_iff_injective, - ← AlgHom.coe_toRingHom, ← hx.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin, - RingHom.coe_comp] - exact Injective.of_comp_iff' (Polynomial.aeval a) - (mvPolynomialOptionEquivPolynomialAdjoin hx).bijective - -/-- Variant of `algebraicIndependent_of_finite` using `Transcendental`. -/ -theorem algebraicIndependent_of_finite' (s : Set A) - (hinj : Injective (algebraMap R A)) - (H : ∀ t ⊆ s, t.Finite → ∀ a ∈ s, a ∉ t → Transcendental (adjoin R t) a) : - AlgebraicIndependent R ((↑) : s → A) := by - classical - refine algebraicIndependent_of_finite s fun t hts hfin ↦ hfin.induction_on' - ((algebraicIndependent_empty_iff R A).2 hinj) fun {a} {u} ha hu ha' h ↦ ?_ - convert ((Subtype.range_coe ▸ h.option_iff a).2 <| H u (hu.trans hts) (hfin.subset hu) - a (hts ha) ha').comp _ (Set.subtypeInsertEquivOption ha').injective - ext x - by_cases h : ↑x = a <;> simp [h, Set.subtypeInsertEquivOption] - -/-- `Type` version of `algebraicIndependent_of_finite'`. -/ -theorem algebraicIndependent_of_finite_type' - (hinj : Injective (algebraMap R A)) - (H : ∀ t : Set ι, t.Finite → ∀ i : ι, i ∉ t → Transcendental (adjoin R (x '' t)) (x i)) : - AlgebraicIndependent R x := by - nontriviality R - haveI := hinj.nontrivial - have hx : Injective x := by - simp_rw [Transcendental] at H - contrapose! H - obtain ⟨i, j, h1, h2⟩ := not_injective_iff.1 H - refine ⟨{j}, by simp, i, by simp [h2], ?_⟩ - rw [h1, Set.image_singleton] - exact isAlgebraic_algebraMap (⟨x j, Algebra.self_mem_adjoin_singleton R _⟩ : adjoin R {x j}) - rw [← Set.coe_comp_rangeFactorization x] - refine .comp (algebraicIndependent_of_finite' _ hinj fun t ht hfin a ha ha' ↦ ?_) _ - (Set.rightInverse_rangeSplitting hx).injective - change Finite t at hfin - have := H (x ⁻¹' t) (Finite.of_injective _ (hx.restrictPreimage t)) - ((Equiv.ofInjective _ hx).symm ⟨_, ha⟩) - (by rwa [Set.mem_preimage, Equiv.apply_ofInjective_symm hx]) - rwa [Set.image_preimage_eq_inter_range, Set.inter_eq_self_of_subset_left ht, - Equiv.apply_ofInjective_symm hx] at this - -namespace MvPolynomial - -/-- If for each `i : ι`, `f_i : R[X]` is transcendental over `R`, then `{f_i(X_i) | i : ι}` -in `MvPolynomial ι R` is algebraically independent over `R`. -/ -theorem algebraicIndependent_polynomial_aeval_X - (f : ι → Polynomial R) (hf : ∀ i, Transcendental R (f i)) : - AlgebraicIndependent R fun i ↦ Polynomial.aeval (X i : MvPolynomial ι R) (f i) := by - set x := fun i ↦ Polynomial.aeval (X i : MvPolynomial ι R) (f i) - refine algebraicIndependent_of_finite_type' (C_injective _ _) fun t _ i hi ↦ ?_ - have hle : adjoin R (x '' t) ≤ supported R t := by - rw [Algebra.adjoin_le_iff, Set.image_subset_iff] - intro _ h - rw [Set.mem_preimage] - refine Algebra.adjoin_mono ?_ (Polynomial.aeval_mem_adjoin_singleton R _) - simp_rw [singleton_subset_iff, Set.mem_image_of_mem _ h] - exact (transcendental_supported_polynomial_aeval_X R hi (hf i)).of_tower_top_of_subalgebra_le hle - -end MvPolynomial - -/-- If `{x_i : A | i : ι}` is algebraically independent over `R`, and for each `i`, -`f_i : R[X]` is transcendental over `R`, then `{f_i(x_i) | i : ι}` is also -algebraically independent over `R`. -/ -theorem AlgebraicIndependent.polynomial_aeval_of_transcendental - (hx : AlgebraicIndependent R x) - {f : ι → Polynomial R} (hf : ∀ i, Transcendental R (f i)) : - AlgebraicIndependent R fun i ↦ Polynomial.aeval (x i) (f i) := by - convert aeval_of_algebraicIndependent hx (algebraicIndependent_polynomial_aeval_X _ hf) - rw [← AlgHom.comp_apply] - congr 1; ext1; simp - -variable (R) - -/-- A family is a transcendence basis if it is a maximal algebraically independent subset. -/ -def IsTranscendenceBasis (x : ι → A) : Prop := - AlgebraicIndependent R x ∧ - ∀ (s : Set A) (_ : AlgebraicIndependent R ((↑) : s → A)) (_ : range x ≤ s), range x = s - -theorem exists_isTranscendenceBasis (h : Injective (algebraMap R A)) : - ∃ s : Set A, IsTranscendenceBasis R ((↑) : s → A) := by - cases' exists_maximal_algebraicIndependent (∅ : Set A) Set.univ (Set.subset_univ _) - ((algebraicIndependent_empty_iff R A).2 h) with - s hs - refine ⟨s, hs.2.1.1, fun t ht hst ↦ ?_⟩ - simp only [Subtype.range_coe_subtype, setOf_mem_eq] at * - exact hs.2.eq_of_le ⟨ht, subset_univ _⟩ hst - -/-- `Type` version of `exists_isTranscendenceBasis`. -/ -theorem exists_isTranscendenceBasis' (R : Type u) {A : Type v} [CommRing R] [CommRing A] - [Algebra R A] (h : Injective (algebraMap R A)) : - ∃ (ι : Type v) (x : ι → A), IsTranscendenceBasis R x := by - obtain ⟨s, h⟩ := exists_isTranscendenceBasis R h - exact ⟨s, Subtype.val, h⟩ - -variable {R} - -theorem AlgebraicIndependent.isTranscendenceBasis_iff {ι : Type w} {R : Type u} [CommRing R] - [Nontrivial R] {A : Type v} [CommRing A] [Algebra R A] {x : ι → A} - (i : AlgebraicIndependent R x) : - IsTranscendenceBasis R x ↔ - ∀ (κ : Type v) (w : κ → A) (_ : AlgebraicIndependent R w) (j : ι → κ) (_ : w ∘ j = x), - Surjective j := by - fconstructor - · rintro p κ w i' j rfl - have p := p.2 (range w) i'.coe_range (range_comp_subset_range _ _) - rw [range_comp, ← @image_univ _ _ w] at p - exact range_eq_univ.mp (image_injective.mpr i'.injective p) - · intro p - use i - intro w i' h - specialize p w ((↑) : w → A) i' (fun i => ⟨x i, range_subset_iff.mp h i⟩) (by ext; simp) - have q := congr_arg (fun s => ((↑) : w → A) '' s) p.range_eq - dsimp at q - rw [← image_univ, image_image] at q - simpa using q - -theorem IsTranscendenceBasis.isAlgebraic [Nontrivial R] (hx : IsTranscendenceBasis R x) : - Algebra.IsAlgebraic (adjoin R (range x)) A := by - constructor - intro a - rw [← not_iff_comm.1 (hx.1.option_iff _).symm] - intro ai - have h₁ : range x ⊆ range fun o : Option ι => o.elim a x := by - rintro x ⟨y, rfl⟩ - exact ⟨some y, rfl⟩ - have h₂ : range x ≠ range fun o : Option ι => o.elim a x := by - intro h - have : a ∈ range x := by - rw [h] - exact ⟨none, rfl⟩ - rcases this with ⟨b, rfl⟩ - have : some b = none := ai.injective rfl - simpa - exact h₂ (hx.2 (Set.range fun o : Option ι => o.elim a x) - ((algebraicIndependent_subtype_range ai.injective).2 ai) h₁) - -/-- If `x` is a transcendence basis of `A/R`, then it is empty if and only if -`A/R` is algebraic. -/ -theorem IsTranscendenceBasis.isEmpty_iff_isAlgebraic [Nontrivial R] - (hx : IsTranscendenceBasis R x) : - IsEmpty ι ↔ Algebra.IsAlgebraic R A := by - refine ⟨fun _ ↦ ?_, fun _ ↦ hx.1.isEmpty_of_isAlgebraic⟩ - have := hx.isAlgebraic - rw [Set.range_eq_empty x, adjoin_empty] at this - exact algebra_isAlgebraic_of_algebra_isAlgebraic_bot_left R A - -/-- If `x` is a transcendence basis of `A/R`, then it is not empty if and only if -`A/R` is transcendental. -/ -theorem IsTranscendenceBasis.nonempty_iff_transcendental [Nontrivial R] - (hx : IsTranscendenceBasis R x) : - Nonempty ι ↔ Algebra.Transcendental R A := by - rw [← not_isEmpty_iff, Algebra.transcendental_iff_not_isAlgebraic, hx.isEmpty_iff_isAlgebraic] - -theorem IsTranscendenceBasis.isAlgebraic_field {F E : Type*} {x : ι → E} - [Field F] [Field E] [Algebra F E] (hx : IsTranscendenceBasis F x) : - Algebra.IsAlgebraic (IntermediateField.adjoin F (range x)) E := by - haveI := hx.isAlgebraic - set S := range x - letI : Algebra (adjoin F S) (IntermediateField.adjoin F S) := - (Subalgebra.inclusion (IntermediateField.algebra_adjoin_le_adjoin F S)).toRingHom.toAlgebra - haveI : IsScalarTower (adjoin F S) (IntermediateField.adjoin F S) E := - IsScalarTower.of_algebraMap_eq (congrFun rfl) - exact Algebra.IsAlgebraic.extendScalars (R := adjoin F S) (Subalgebra.inclusion_injective _) - -section Field - -variable [Field K] [Algebra K A] - -/- Porting note: removing `simp`, not in simp normal form. Could make `Function.Injective f` a -simp lemma when `f` is a field hom, and then simp would prove this -/ -theorem algebraicIndependent_empty_type [IsEmpty ι] [Nontrivial A] : AlgebraicIndependent K x := by - rw [algebraicIndependent_empty_type_iff] - exact RingHom.injective _ - -theorem algebraicIndependent_empty [Nontrivial A] : - AlgebraicIndependent K ((↑) : (∅ : Set A) → A) := - algebraicIndependent_empty_type - -end Field - -section RankAndCardinality - -open Cardinal - -theorem IsTranscendenceBasis.lift_cardinalMk_eq_max_lift - {F : Type u} {E : Type v} [CommRing F] [Nontrivial F] [CommRing E] [IsDomain E] [Algebra F E] - {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : - lift.{max u w} #E = lift.{max v w} #F ⊔ lift.{max u v} #ι ⊔ ℵ₀ := by - let K := Algebra.adjoin F (Set.range x) - suffices #E = #K by simp [this, ← lift_mk_eq'.2 ⟨hx.1.aevalEquiv.toEquiv⟩] - haveI : Algebra.IsAlgebraic K E := hx.isAlgebraic - refine le_antisymm ?_ (mk_le_of_injective Subtype.val_injective) - haveI : Infinite K := hx.1.aevalEquiv.infinite_iff.1 inferInstance - simpa only [sup_eq_left.2 (aleph0_le_mk K)] using Algebra.IsAlgebraic.cardinalMk_le_max K E - -theorem IsTranscendenceBasis.lift_rank_eq_max_lift - {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] - {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : - lift.{max u w} (Module.rank F E) = lift.{max v w} #F ⊔ lift.{max u v} #ι ⊔ ℵ₀ := by - let K := IntermediateField.adjoin F (Set.range x) - haveI : Algebra.IsAlgebraic K E := hx.isAlgebraic_field - rw [← rank_mul_rank F K E, lift_mul, ← hx.1.aevalEquivField.toLinearEquiv.lift_rank_eq, - MvRatFunc.rank_eq_max_lift, lift_max, lift_max, lift_lift, lift_lift, lift_aleph0] - refine mul_eq_left le_sup_right ((lift_le.2 ((rank_le_card K E).trans - (Algebra.IsAlgebraic.cardinalMk_le_max K E))).trans_eq ?_) (by simp [rank_pos.ne']) - simp [← lift_mk_eq'.2 ⟨hx.1.aevalEquivField.toEquiv⟩] - -theorem Algebra.Transcendental.rank_eq_cardinalMk - (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] [Algebra.Transcendental F E] : - Module.rank F E = #E := by - obtain ⟨ι, x, hx⟩ := exists_isTranscendenceBasis' _ (algebraMap F E).injective - haveI := hx.nonempty_iff_transcendental.2 ‹_› - simpa [← hx.lift_cardinalMk_eq_max_lift] using hx.lift_rank_eq_max_lift - -theorem IntermediateField.rank_sup_le - {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (A B : IntermediateField F E) : - Module.rank F ↥(A ⊔ B) ≤ Module.rank F A * Module.rank F B := by - by_cases hA : Algebra.IsAlgebraic F A - · exact rank_sup_le_of_isAlgebraic A B (Or.inl hA) - by_cases hB : Algebra.IsAlgebraic F B - · exact rank_sup_le_of_isAlgebraic A B (Or.inr hB) - rw [← Algebra.transcendental_iff_not_isAlgebraic] at hA hB - haveI : Algebra.Transcendental F ↥(A ⊔ B) := .ringHom_of_comp_eq (RingHom.id F) - (inclusion le_sup_left) Function.surjective_id (inclusion_injective _) rfl - haveI := Algebra.Transcendental.infinite F A - haveI := Algebra.Transcendental.infinite F B - simp_rw [Algebra.Transcendental.rank_eq_cardinalMk] - rw [sup_def, mul_mk_eq_max, ← Cardinal.lift_le.{u}] - refine (lift_cardinalMk_adjoin_le _ _).trans ?_ - calc - _ ≤ Cardinal.lift.{v} #F ⊔ Cardinal.lift.{u} (#A ⊔ #B) ⊔ ℵ₀ := by - gcongr - rw [Cardinal.lift_le] - exact (mk_union_le _ _).trans_eq (by simp) - _ = _ := by - simp [lift_mk_le_lift_mk_of_injective (algebraMap F A).injective] - -end RankAndCardinality diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Adjoin.lean b/Mathlib/RingTheory/AlgebraicIndependent/Adjoin.lean new file mode 100644 index 0000000000000..53d2a48d0cf9b --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/Adjoin.lean @@ -0,0 +1,71 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.FieldTheory.Adjoin +import Mathlib.RingTheory.AlgebraicIndependent.Defs + +/-! +# Algebraic Independence + +This file concerns adjoining an algebraic independent family to a field. + +## Main definitions + +* `AlgebraicIndependent.aevalEquivField` - The canonical isomorphism from the rational function + field ring to the intermediate field generated by an algebraic independent family. + +* `AlgebraicIndependent.reprField` - The canonical map from the intermediate field generated by an + algebraic independent family into the rational function field. It is the inverse of + `AlgebraicIndependent.aevalEquivField`. +-/ + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +namespace AlgebraicIndependent + +variable {ι : Type*} +variable {F E : Type*} {x : ι → E} [Field F] [Field E] [Algebra F E] (hx : AlgebraicIndependent F x) +include hx + +/-- Canonical isomorphism between rational function field and the + intermediate field generated by algebraically independent elements. -/ +def aevalEquivField : + FractionRing (MvPolynomial ι F) ≃ₐ[F] ↥(IntermediateField.adjoin F (range x)) := + let i := IsFractionRing.liftAlgHom (K := FractionRing (MvPolynomial ι F)) + (algebraicIndependent_iff_injective_aeval.2 hx) + (show _ ≃ₐ[F] i.fieldRange from AlgEquiv.ofInjectiveField i).trans <| + IntermediateField.equivOfEq <| + IsFractionRing.algHom_fieldRange_eq_of_comp_eq_of_range_eq (g := aeval x) (f := i) + (by ext <;> simp [i]) (Algebra.adjoin_range_eq_range_aeval F x).symm + +@[simp] +theorem aevalEquivField_apply_coe (a : FractionRing (MvPolynomial ι F)) : + hx.aevalEquivField a = + IsFractionRing.lift (algebraicIndependent_iff_injective_aeval.2 hx) a := rfl + +theorem aevalEquivField_algebraMap_apply_coe (a : MvPolynomial ι F) : + hx.aevalEquivField (algebraMap _ _ a) = aeval x a := by + simp + +/-- The canonical map from the intermediate field generated by an algebraic independent family + into the rational function field. -/ +def reprField : IntermediateField.adjoin F (range x) →ₐ[F] FractionRing (MvPolynomial ι F) := + hx.aevalEquivField.symm + +@[simp] +theorem lift_reprField (p) : + IsFractionRing.lift (algebraicIndependent_iff_injective_aeval.2 hx) (hx.reprField p) = p := + Subtype.ext_iff.1 (AlgEquiv.apply_symm_apply hx.aevalEquivField p) + +theorem liftAlgHom_comp_reprField : + (IsFractionRing.liftAlgHom (algebraicIndependent_iff_injective_aeval.2 hx)).comp hx.reprField = + IntermediateField.val _ := + AlgHom.ext <| hx.lift_reprField + +end AlgebraicIndependent diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean b/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean new file mode 100644 index 0000000000000..605ac77d46b2a --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/Basic.lean @@ -0,0 +1,384 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.Algebra.MvPolynomial.Equiv +import Mathlib.Algebra.MvPolynomial.Monad +import Mathlib.Algebra.MvPolynomial.Supported +import Mathlib.RingTheory.AlgebraicIndependent.Defs +import Mathlib.RingTheory.Ideal.Maps +import Mathlib.RingTheory.MvPolynomial.Basic + +/-! +# Algebraic Independence + +This file contains basic results on algebraic independence of a family of elements of an `R`-algebra + +## References + +* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) + +## TODO +Define the transcendence degree and show it is independent of the choice of a +transcendence basis. + +## Tags +transcendence basis, transcendence degree, transcendence + +-/ + + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +variable {ι ι' R K A A' : Type*} {x : ι → A} +variable [CommRing R] [CommRing A] [CommRing A'] [Algebra R A] [Algebra R A'] + +theorem algebraicIndependent_iff_ker_eq_bot : + AlgebraicIndependent R x ↔ + RingHom.ker (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A).toRingHom = ⊥ := + RingHom.injective_iff_ker_eq_bot _ + +@[simp] +theorem algebraicIndependent_empty_type_iff [IsEmpty ι] : + AlgebraicIndependent R x ↔ Injective (algebraMap R A) := by + rw [algebraicIndependent_iff_injective_aeval, MvPolynomial.aeval_injective_iff_of_isEmpty] + +namespace AlgebraicIndependent + +variable (hx : AlgebraicIndependent R x) +include hx + +theorem algebraMap_injective : Injective (algebraMap R A) := by + simpa [Function.comp_def] using + (Injective.of_comp_iff (algebraicIndependent_iff_injective_aeval.1 hx) MvPolynomial.C).2 + (MvPolynomial.C_injective _ _) + +theorem linearIndependent : LinearIndependent R x := by + rw [linearIndependent_iff_injective_linearCombination] + have : Finsupp.linearCombination R x = + (MvPolynomial.aeval x).toLinearMap.comp (Finsupp.linearCombination R X) := by + ext + simp + rw [this] + refine (algebraicIndependent_iff_injective_aeval.mp hx).comp ?_ + rw [← linearIndependent_iff_injective_linearCombination] + exact linearIndependent_X _ _ + +protected theorem injective [Nontrivial R] : Injective x := + hx.linearIndependent.injective + +theorem ne_zero [Nontrivial R] (i : ι) : x i ≠ 0 := + hx.linearIndependent.ne_zero i + +theorem map {f : A →ₐ[R] A'} (hf_inj : Set.InjOn f (adjoin R (range x))) : + AlgebraicIndependent R (f ∘ x) := by + have : aeval (f ∘ x) = f.comp (aeval x) := by ext; simp + have h : ∀ p : MvPolynomial ι R, aeval x p ∈ (@aeval R _ _ _ _ _ ((↑) : range x → A)).range := by + intro p + rw [AlgHom.mem_range] + refine ⟨MvPolynomial.rename (codRestrict x (range x) mem_range_self) p, ?_⟩ + simp [Function.comp_def, aeval_rename] + intro x y hxy + rw [this] at hxy + rw [adjoin_eq_range] at hf_inj + exact hx (hf_inj (h x) (h y) hxy) + +theorem map' {f : A →ₐ[R] A'} (hf_inj : Injective f) : AlgebraicIndependent R (f ∘ x) := + hx.map hf_inj.injOn + +/-- If `x = {x_i : A | i : ι}` and `f = {f_i : MvPolynomial ι R | i : ι}` are algebraically +independent over `R`, then `{f_i(x) | i : ι}` is also algebraically independent over `R`. +For the partial converse, see `AlgebraicIndependent.of_aeval`. -/ +theorem aeval_of_algebraicIndependent + {f : ι → MvPolynomial ι R} (hf : AlgebraicIndependent R f) : + AlgebraicIndependent R fun i ↦ aeval x (f i) := by + rw [algebraicIndependent_iff] at hx hf ⊢ + intro p hp + exact hf _ (hx _ (by rwa [← aeval_comp_bind₁, AlgHom.comp_apply] at hp)) + +omit hx in +/-- If `{f_i(x) | i : ι}` is algebraically independent over `R`, then +`{f_i : MvPolynomial ι R | i : ι}` is also algebraically independent over `R`. +In fact, the `x = {x_i : A | i : ι}` is also transcendental over `R` provided that `R` +is a field and `ι` is finite; the proof needs transcendence degree. -/ +theorem of_aeval {f : ι → MvPolynomial ι R} + (H : AlgebraicIndependent R fun i ↦ aeval x (f i)) : + AlgebraicIndependent R f := by + rw [algebraicIndependent_iff] at H ⊢ + intro p hp + exact H p (by rw [← aeval_comp_bind₁, AlgHom.comp_apply, bind₁, hp, map_zero]) + +end AlgebraicIndependent + +theorem MvPolynomial.algebraicIndependent_X (σ R : Type*) [CommRing R] : + AlgebraicIndependent R (X (R := R) (σ := σ)) := by + rw [AlgebraicIndependent, aeval_X_left] + exact injective_id + +open AlgebraicIndependent + +theorem AlgHom.algebraicIndependent_iff (f : A →ₐ[R] A') (hf : Injective f) : + AlgebraicIndependent R (f ∘ x) ↔ AlgebraicIndependent R x := + ⟨fun h => h.of_comp f, fun h => h.map hf.injOn⟩ + +@[nontriviality] +theorem algebraicIndependent_of_subsingleton [Subsingleton R] : AlgebraicIndependent R x := + algebraicIndependent_iff.2 fun _ _ => Subsingleton.elim _ _ + +theorem algebraicIndependent_adjoin (hs : AlgebraicIndependent R x) : + @AlgebraicIndependent ι R (adjoin R (range x)) + (fun i : ι => ⟨x i, subset_adjoin (mem_range_self i)⟩) _ _ _ := + AlgebraicIndependent.of_comp (adjoin R (range x)).val hs + +/-- A set of algebraically independent elements in an algebra `A` over a ring `K` is also +algebraically independent over a subring `R` of `K`. -/ +theorem AlgebraicIndependent.restrictScalars {K : Type*} [CommRing K] [Algebra R K] [Algebra K A] + [IsScalarTower R K A] (hinj : Function.Injective (algebraMap R K)) + (ai : AlgebraicIndependent K x) : AlgebraicIndependent R x := by + have : (aeval x : MvPolynomial ι K →ₐ[K] A).toRingHom.comp (MvPolynomial.map (algebraMap R K)) = + (aeval x : MvPolynomial ι R →ₐ[R] A).toRingHom := by + ext <;> simp [algebraMap_eq_smul_one] + show Injective (aeval x).toRingHom + rw [← this, RingHom.coe_comp] + exact Injective.comp ai (MvPolynomial.map_injective _ hinj) + +section RingHom + +variable {S B FRS FAB : Type*} [CommRing S] [CommRing B] [Algebra S B] + +section + +variable [FunLike FRS R S] [RingHomClass FRS R S] [FunLike FAB A B] [RingHomClass FAB A B] + (f : FRS) (g : FAB) + +theorem AlgebraicIndependent.of_ringHom_of_comp_eq (H : AlgebraicIndependent S (g ∘ x)) + (hf : Function.Injective f) + (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : + AlgebraicIndependent R x := by + rw [algebraicIndependent_iff] at H ⊢ + intro p hp + have := H (p.map f) <| by + have : (g : A →+* B) _ = _ := congr(g $hp) + rwa [map_zero, map_aeval, ← h, ← eval₂Hom_map_hom, ← aeval_eq_eval₂Hom] at this + exact map_injective (f : R →+* S) hf (by rwa [map_zero]) + +theorem AlgebraicIndependent.ringHom_of_comp_eq (H : AlgebraicIndependent R x) + (hf : Function.Surjective f) (hg : Function.Injective g) + (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : + AlgebraicIndependent S (g ∘ x) := by + rw [algebraicIndependent_iff] at H ⊢ + intro p hp + obtain ⟨q, rfl⟩ := map_surjective (f : R →+* S) hf p + rw [H q (hg (by rwa [map_zero, ← RingHom.coe_coe g, map_aeval, ← h, ← eval₂Hom_map_hom, + ← aeval_eq_eval₂Hom])), map_zero] + +end + +section + +variable [EquivLike FRS R S] [RingEquivClass FRS R S] [FunLike FAB A B] [RingHomClass FAB A B] + (f : FRS) (g : FAB) + +theorem algebraicIndependent_ringHom_iff_of_comp_eq + (hg : Function.Injective g) + (h : RingHom.comp (algebraMap S B) f = RingHom.comp g (algebraMap R A)) : + AlgebraicIndependent S (g ∘ x) ↔ AlgebraicIndependent R x := + ⟨fun H ↦ H.of_ringHom_of_comp_eq f g (EquivLike.injective f) h, + fun H ↦ H.ringHom_of_comp_eq f g (EquivLike.surjective f) hg h⟩ + +end + +end RingHom + +/-- Every finite subset of an algebraically independent set is algebraically independent. -/ +theorem algebraicIndependent_finset_map_embedding_subtype (s : Set A) + (li : AlgebraicIndependent R ((↑) : s → A)) (t : Finset s) : + AlgebraicIndependent R ((↑) : Finset.map (Embedding.subtype s) t → A) := by + let f : t.map (Embedding.subtype s) → s := fun x => + ⟨x.1, by + obtain ⟨x, h⟩ := x + rw [Finset.mem_map] at h + obtain ⟨a, _, rfl⟩ := h + simp only [Subtype.coe_prop, Embedding.coe_subtype]⟩ + convert AlgebraicIndependent.comp li f _ + rintro ⟨x, hx⟩ ⟨y, hy⟩ + rw [Finset.mem_map] at hx hy + obtain ⟨a, _, rfl⟩ := hx + obtain ⟨b, _, rfl⟩ := hy + simp only [f, imp_self, Subtype.mk_eq_mk] + +/-- If every finite set of algebraically independent element has cardinality at most `n`, +then the same is true for arbitrary sets of algebraically independent elements. -/ +theorem algebraicIndependent_bounded_of_finset_algebraicIndependent_bounded {n : ℕ} + (H : ∀ s : Finset A, (AlgebraicIndependent R fun i : s => (i : A)) → s.card ≤ n) : + ∀ s : Set A, AlgebraicIndependent R ((↑) : s → A) → Cardinal.mk s ≤ n := by + intro s li + apply Cardinal.card_le_of + intro t + rw [← Finset.card_map (Embedding.subtype s)] + apply H + apply algebraicIndependent_finset_map_embedding_subtype _ li + +section Subtype + +theorem AlgebraicIndependent.restrict_of_comp_subtype {s : Set ι} + (hs : AlgebraicIndependent R (x ∘ (↑) : s → A)) : AlgebraicIndependent R (s.restrict x) := + hs + +variable (R A) + +theorem algebraicIndependent_empty_iff : + AlgebraicIndependent R ((↑) : (∅ : Set A) → A) ↔ Injective (algebraMap R A) := by simp + +end Subtype + +theorem AlgebraicIndependent.to_subtype_range {ι} {f : ι → A} (hf : AlgebraicIndependent R f) : + AlgebraicIndependent R ((↑) : range f → A) := by + nontriviality R + rwa [algebraicIndependent_subtype_range hf.injective] + +theorem AlgebraicIndependent.to_subtype_range' {ι} {f : ι → A} (hf : AlgebraicIndependent R f) {t} + (ht : range f = t) : AlgebraicIndependent R ((↑) : t → A) := + ht ▸ hf.to_subtype_range + +theorem algebraicIndependent_comp_subtype {s : Set ι} : + AlgebraicIndependent R (x ∘ (↑) : s → A) ↔ + ∀ p ∈ MvPolynomial.supported R s, aeval x p = 0 → p = 0 := by + have : (aeval (x ∘ (↑) : s → A) : _ →ₐ[R] _) = (aeval x).comp (rename (↑)) := by ext; simp + have : ∀ p : MvPolynomial s R, rename ((↑) : s → ι) p = 0 ↔ p = 0 := + (injective_iff_map_eq_zero' (rename ((↑) : s → ι) : MvPolynomial s R →ₐ[R] _).toRingHom).1 + (rename_injective _ Subtype.val_injective) + simp [algebraicIndependent_iff, supported_eq_range_rename, *] + +theorem algebraicIndependent_subtype {s : Set A} : + AlgebraicIndependent R ((↑) : s → A) ↔ + ∀ p : MvPolynomial A R, p ∈ MvPolynomial.supported R s → aeval id p = 0 → p = 0 := by + apply @algebraicIndependent_comp_subtype _ _ _ id + +theorem algebraicIndependent_of_finite (s : Set 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) + +theorem AlgebraicIndependent.image_of_comp {ι ι'} (s : Set ι) (f : ι → ι') (g : ι' → A) + (hs : AlgebraicIndependent R fun x : s => g (f x)) : + AlgebraicIndependent R fun x : f '' s => g x := by + nontriviality R + have : InjOn f s := injOn_iff_injective.2 hs.injective.of_comp + exact (algebraicIndependent_equiv' (Equiv.Set.imageOfInjOn f s this) rfl).1 hs + +theorem AlgebraicIndependent.image {ι} {s : Set ι} {f : ι → A} + (hs : AlgebraicIndependent R fun x : s => f x) : + AlgebraicIndependent R fun x : f '' s => (x : A) := by + convert AlgebraicIndependent.image_of_comp s f id hs + +theorem algebraicIndependent_iUnion_of_directed {η : Type*} [Nonempty η] {s : η → Set A} + (hs : Directed (· ⊆ ·) s) (h : ∀ i, AlgebraicIndependent R ((↑) : s i → A)) : + AlgebraicIndependent R ((↑) : (⋃ i, s i) → A) := by + refine algebraicIndependent_of_finite (⋃ i, s i) fun t ht ft => ?_ + rcases finite_subset_iUnion ft ht with ⟨I, fi, hI⟩ + rcases hs.finset_le fi.toFinset with ⟨i, hi⟩ + exact (h i).mono (Subset.trans hI <| iUnion₂_subset fun j hj => hi j (fi.mem_toFinset.2 hj)) + +theorem algebraicIndependent_sUnion_of_directed {s : Set (Set A)} (hsn : s.Nonempty) + (hs : DirectedOn (· ⊆ ·) s) (h : ∀ a ∈ s, AlgebraicIndependent R ((↑) : a → A)) : + AlgebraicIndependent R ((↑) : ⋃₀ s → A) := by + letI : Nonempty s := Nonempty.to_subtype hsn + rw [sUnion_eq_iUnion] + exact algebraicIndependent_iUnion_of_directed hs.directed_val (by simpa using h) + +theorem exists_maximal_algebraicIndependent (s t : Set A) (hst : s ⊆ t) + (hs : AlgebraicIndependent R ((↑) : s → A)) : ∃ u, s ⊆ u ∧ + Maximal (fun (x : Set A) ↦ AlgebraicIndependent R ((↑) : x → A) ∧ x ⊆ t) u := by + refine zorn_subset_nonempty { u : Set A | AlgebraicIndependent R ((↑) : u → A) ∧ u ⊆ t} + (fun c hc chainc hcn ↦ ⟨⋃₀ c, ⟨?_, ?_⟩, fun _ ↦ subset_sUnion_of_mem⟩) s ⟨hs, hst⟩ + · exact algebraicIndependent_sUnion_of_directed hcn chainc.directedOn (fun x hxc ↦ (hc hxc).1) + exact fun x ⟨w, hyc, hwy⟩ ↦ (hc hyc).2 hwy + +theorem AlgebraicIndependent.repr_ker (hx : AlgebraicIndependent R x) : + RingHom.ker (hx.repr : adjoin R (range x) →+* MvPolynomial ι R) = ⊥ := + (RingHom.injective_iff_ker_eq_bot _).1 (AlgEquiv.injective _) + +-- TODO - make this an `AlgEquiv` +/-- The isomorphism between `MvPolynomial (Option ι) R` and the polynomial ring over +the algebra generated by an algebraically independent family. -/ +def AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin (hx : AlgebraicIndependent R x) : + MvPolynomial (Option ι) R ≃+* Polynomial (adjoin R (Set.range x)) := + (MvPolynomial.optionEquivLeft _ _).toRingEquiv.trans + (Polynomial.mapEquiv hx.aevalEquiv.toRingEquiv) + +@[simp] +theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply + (hx : AlgebraicIndependent R x) (y) : + hx.mvPolynomialOptionEquivPolynomialAdjoin y = + Polynomial.map (hx.aevalEquiv : MvPolynomial ι R →+* adjoin R (range x)) + (aeval (fun o : Option ι => o.elim Polynomial.X fun s : ι => Polynomial.C (X s)) y) := + rfl + +/-- `simp`-normal form of `mvPolynomialOptionEquivPolynomialAdjoin_C` -/ +@[simp] +theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_C' + (hx : AlgebraicIndependent R x) (r) : + Polynomial.C (hx.aevalEquiv (C r)) = Polynomial.C (algebraMap _ _ r) := by + congr + apply_fun Subtype.val using Subtype.val_injective + simp + +theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_C + (hx : AlgebraicIndependent R x) (r) : + hx.mvPolynomialOptionEquivPolynomialAdjoin (C r) = Polynomial.C (algebraMap _ _ r) := by + simp + +theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_X_none + (hx : AlgebraicIndependent R x) : + hx.mvPolynomialOptionEquivPolynomialAdjoin (X none) = Polynomial.X := by + rw [AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply, aeval_X, Option.elim, + Polynomial.map_X] + +theorem AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_X_some + (hx : AlgebraicIndependent R x) (i) : + hx.mvPolynomialOptionEquivPolynomialAdjoin (X (some i)) = + Polynomial.C (hx.aevalEquiv (X i)) := by + rw [AlgebraicIndependent.mvPolynomialOptionEquivPolynomialAdjoin_apply, aeval_X, Option.elim, + Polynomial.map_C, RingHom.coe_coe] + +theorem AlgebraicIndependent.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin + (hx : AlgebraicIndependent R x) (a : A) : + RingHom.comp + (↑(Polynomial.aeval a : Polynomial (adjoin R (Set.range x)) →ₐ[_] A) : + Polynomial (adjoin R (Set.range x)) →+* A) + hx.mvPolynomialOptionEquivPolynomialAdjoin.toRingHom = + ↑(MvPolynomial.aeval fun o : Option ι => o.elim a x : MvPolynomial (Option ι) R →ₐ[R] A) := by + refine MvPolynomial.ringHom_ext ?_ ?_ <;> + simp only [RingHom.comp_apply, RingEquiv.toRingHom_eq_coe, RingEquiv.coe_toRingHom, + AlgHom.coe_toRingHom, AlgHom.coe_toRingHom] + · intro r + rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_C, aeval_C, Polynomial.aeval_C, + IsScalarTower.algebraMap_apply R (adjoin R (range x)) A] + · rintro (⟨⟩ | ⟨i⟩) + · rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_X_none, aeval_X, Polynomial.aeval_X, + Option.elim] + · rw [hx.mvPolynomialOptionEquivPolynomialAdjoin_X_some, Polynomial.aeval_C, + hx.algebraMap_aevalEquiv, aeval_X, aeval_X, Option.elim] + +section Field + +variable [Field K] [Algebra K A] + +/- Porting note: removing `simp`, not in simp normal form. Could make `Function.Injective f` a +simp lemma when `f` is a field hom, and then simp would prove this -/ +theorem algebraicIndependent_empty_type [IsEmpty ι] [Nontrivial A] : AlgebraicIndependent K x := by + rw [algebraicIndependent_empty_type_iff] + exact RingHom.injective _ + +theorem algebraicIndependent_empty [Nontrivial A] : + AlgebraicIndependent K ((↑) : (∅ : Set A) → A) := + algebraicIndependent_empty_type + +end Field diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Defs.lean b/Mathlib/RingTheory/AlgebraicIndependent/Defs.lean new file mode 100644 index 0000000000000..c3d9b6df75314 --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/Defs.lean @@ -0,0 +1,155 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.Algebra.MvPolynomial.CommRing + +/-! +# Algebraic Independence + +This file defines algebraic independence of a family of elements of an `R` algebra. + +## Main definitions + +* `AlgebraicIndependent` - `AlgebraicIndependent R x` states the family of elements `x` + is algebraically independent over `R`, meaning that the canonical map out of the multivariable + polynomial ring is injective. + +* `AlgebraicIndependent.aevalEquiv` - The canonical isomorphism from the polynomial ring to the + subalgebra generated by an algebraic independent family. + +* `AlgebraicIndependent.repr` - The canonical map from the subalgebra generated by an + algebraic independent family into the polynomial ring. It is the inverse of + `AlgebraicIndependent.aevalEquiv`. + +* `IsTranscendenceBasis R x` - a family `x` is a transcendence basis over `R` if it is a maximal + algebraically independent subset. + +## Main results + +We show that algebraic independence is preserved under injective maps of the indices. + +## References + +* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) + +-/ + + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +variable {ι ι' : Type*} (R : Type*) {K A A' : Type*} (x : ι → A) +variable [CommRing R] [CommRing A] [CommRing A'] [Algebra R A] [Algebra R A'] + +/-- `AlgebraicIndependent R x` states the family of elements `x` + is algebraically independent over `R`, meaning that the canonical + map out of the multivariable polynomial ring is injective. -/ +def AlgebraicIndependent : Prop := + Injective (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A) + +variable {R} {x} + +theorem algebraicIndependent_iff : + AlgebraicIndependent R x ↔ + ∀ p : MvPolynomial ι R, MvPolynomial.aeval (x : ι → A) p = 0 → p = 0 := + injective_iff_map_eq_zero _ + +theorem AlgebraicIndependent.eq_zero_of_aeval_eq_zero (h : AlgebraicIndependent R x) : + ∀ p : MvPolynomial ι R, MvPolynomial.aeval (x : ι → A) p = 0 → p = 0 := + algebraicIndependent_iff.1 h + +theorem algebraicIndependent_iff_injective_aeval : + AlgebraicIndependent R x ↔ Injective (MvPolynomial.aeval x : MvPolynomial ι R →ₐ[R] A) := + Iff.rfl + +namespace AlgebraicIndependent + +theorem of_comp (f : A →ₐ[R] A') (hfv : AlgebraicIndependent R (f ∘ x)) : + AlgebraicIndependent R x := by + have : aeval (f ∘ x) = f.comp (aeval x) := by ext; simp + rw [AlgebraicIndependent, this, AlgHom.coe_comp] at hfv + exact hfv.of_comp + +variable (hx : AlgebraicIndependent R x) +include hx + +theorem comp (f : ι' → ι) (hf : Function.Injective f) : AlgebraicIndependent R (x ∘ f) := by + intro p q + simpa [aeval_rename, (rename_injective f hf).eq_iff] using @hx (rename f p) (rename f q) + +theorem coe_range : AlgebraicIndependent R ((↑) : range x → A) := by + simpa using hx.comp _ (rangeSplitting_injective x) + +end AlgebraicIndependent + +open AlgebraicIndependent + +theorem algebraicIndependent_equiv (e : ι ≃ ι') {f : ι' → A} : + AlgebraicIndependent R (f ∘ e) ↔ AlgebraicIndependent R f := + ⟨fun h => Function.comp_id f ▸ e.self_comp_symm ▸ h.comp _ e.symm.injective, + fun h => h.comp _ e.injective⟩ + +theorem algebraicIndependent_equiv' (e : ι ≃ ι') {f : ι' → A} {g : ι → A} (h : f ∘ e = g) : + AlgebraicIndependent R g ↔ AlgebraicIndependent R f := + h ▸ algebraicIndependent_equiv e + +theorem algebraicIndependent_subtype_range {ι} {f : ι → A} (hf : Injective f) : + AlgebraicIndependent R ((↑) : range f → A) ↔ AlgebraicIndependent R f := + Iff.symm <| algebraicIndependent_equiv' (Equiv.ofInjective f hf) rfl + +alias ⟨AlgebraicIndependent.of_subtype_range, _⟩ := algebraicIndependent_subtype_range + +theorem algebraicIndependent_image {ι} {s : Set ι} {f : ι → A} (hf : Set.InjOn f s) : + (AlgebraicIndependent R fun x : s => f x) ↔ AlgebraicIndependent R fun x : f '' s => (x : A) := + algebraicIndependent_equiv' (Equiv.Set.imageOfInjOn _ _ hf) rfl + +namespace AlgebraicIndependent + +theorem mono {t s : Set A} (h : t ⊆ s) + (hx : AlgebraicIndependent R ((↑) : s → A)) : AlgebraicIndependent R ((↑) : t → A) := by + simpa [Function.comp] using hx.comp (inclusion h) (inclusion_injective h) + +section repr + +variable (hx : AlgebraicIndependent R x) +include hx + +/-- Canonical isomorphism between polynomials and the subalgebra generated by + algebraically independent elements. -/ +@[simps! apply_coe] +def aevalEquiv : MvPolynomial ι R ≃ₐ[R] Algebra.adjoin R (range x) := + (AlgEquiv.ofInjective (aeval x) (algebraicIndependent_iff_injective_aeval.1 hx)).trans + (Subalgebra.equivOfEq _ _ (Algebra.adjoin_range_eq_range_aeval R x).symm) + +--@[simp] Porting note: removing simp because the linter complains about deterministic timeout +theorem algebraMap_aevalEquiv (p : MvPolynomial ι R) : + algebraMap (Algebra.adjoin R (range x)) A (hx.aevalEquiv p) = aeval x p := + rfl + +/-- The canonical map from the subalgebra generated by an algebraic independent family + into the polynomial ring. -/ +def repr : Algebra.adjoin R (range x) →ₐ[R] MvPolynomial ι R := + hx.aevalEquiv.symm + +@[simp] +theorem aeval_repr (p) : aeval x (hx.repr p) = p := + Subtype.ext_iff.1 (AlgEquiv.apply_symm_apply hx.aevalEquiv p) + +theorem aeval_comp_repr : (aeval x).comp hx.repr = Subalgebra.val _ := + AlgHom.ext hx.aeval_repr + +end repr + +end AlgebraicIndependent + +variable (R) + +/-- A family is a transcendence basis if it is a maximal algebraically independent subset. -/ +def IsTranscendenceBasis (x : ι → A) : Prop := + AlgebraicIndependent R x ∧ + ∀ (s : Set A) (_ : AlgebraicIndependent R ((↑) : s → A)) (_ : range x ≤ s), range x = s diff --git a/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean b/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean new file mode 100644 index 0000000000000..1c736c384c401 --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/RankAndCardinality.lean @@ -0,0 +1,93 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.FieldTheory.MvRatFunc.Rank +import Mathlib.RingTheory.Algebraic.Cardinality +import Mathlib.RingTheory.AlgebraicIndependent.Adjoin +import Mathlib.RingTheory.AlgebraicIndependent.Transcendental +import Mathlib.RingTheory.AlgebraicIndependent.TranscendenceBasis + +/-! +# Cardinality of a transcendence basis + +This file concerns the cardinality of a transcendence basis. + +## References + +* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) + +## TODO +Define the transcendence degree and show it is independent of the choice of a +transcendence basis. + +## Tags +transcendence basis, transcendence degree, transcendence + +-/ + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +universe u v w + +open AlgebraicIndependent + +open Cardinal + +theorem IsTranscendenceBasis.lift_cardinalMk_eq_max_lift + {F : Type u} {E : Type v} [CommRing F] [Nontrivial F] [CommRing E] [IsDomain E] [Algebra F E] + {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : + lift.{max u w} #E = lift.{max v w} #F ⊔ lift.{max u v} #ι ⊔ ℵ₀ := by + let K := Algebra.adjoin F (Set.range x) + suffices #E = #K by simp [K, this, ← lift_mk_eq'.2 ⟨hx.1.aevalEquiv.toEquiv⟩] + haveI : Algebra.IsAlgebraic K E := hx.isAlgebraic + refine le_antisymm ?_ (mk_le_of_injective Subtype.val_injective) + haveI : Infinite K := hx.1.aevalEquiv.infinite_iff.1 inferInstance + simpa only [sup_eq_left.2 (aleph0_le_mk K)] using Algebra.IsAlgebraic.cardinalMk_le_max K E + +theorem IsTranscendenceBasis.lift_rank_eq_max_lift + {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] + {ι : Type w} {x : ι → E} [Nonempty ι] (hx : IsTranscendenceBasis F x) : + lift.{max u w} (Module.rank F E) = lift.{max v w} #F ⊔ lift.{max u v} #ι ⊔ ℵ₀ := by + let K := IntermediateField.adjoin F (Set.range x) + haveI : Algebra.IsAlgebraic K E := hx.isAlgebraic_field + rw [← rank_mul_rank F K E, lift_mul, ← hx.1.aevalEquivField.toLinearEquiv.lift_rank_eq, + MvRatFunc.rank_eq_max_lift, lift_max, lift_max, lift_lift, lift_lift, lift_aleph0] + refine mul_eq_left le_sup_right ((lift_le.2 ((rank_le_card K E).trans + (Algebra.IsAlgebraic.cardinalMk_le_max K E))).trans_eq ?_) (by simp [rank_pos.ne']) + simp [K, ← lift_mk_eq'.2 ⟨hx.1.aevalEquivField.toEquiv⟩] + +theorem Algebra.Transcendental.rank_eq_cardinalMk + (F : Type u) (E : Type v) [Field F] [Field E] [Algebra F E] [Algebra.Transcendental F E] : + Module.rank F E = #E := by + obtain ⟨ι, x, hx⟩ := exists_isTranscendenceBasis' _ (algebraMap F E).injective + haveI := hx.nonempty_iff_transcendental.2 ‹_› + simpa [← hx.lift_cardinalMk_eq_max_lift] using hx.lift_rank_eq_max_lift + +theorem IntermediateField.rank_sup_le + {F : Type u} {E : Type v} [Field F] [Field E] [Algebra F E] (A B : IntermediateField F E) : + Module.rank F ↥(A ⊔ B) ≤ Module.rank F A * Module.rank F B := by + by_cases hA : Algebra.IsAlgebraic F A + · exact rank_sup_le_of_isAlgebraic A B (Or.inl hA) + by_cases hB : Algebra.IsAlgebraic F B + · exact rank_sup_le_of_isAlgebraic A B (Or.inr hB) + rw [← Algebra.transcendental_iff_not_isAlgebraic] at hA hB + haveI : Algebra.Transcendental F ↥(A ⊔ B) := .ringHom_of_comp_eq (RingHom.id F) + (inclusion le_sup_left) Function.surjective_id (inclusion_injective _) rfl + haveI := Algebra.Transcendental.infinite F A + haveI := Algebra.Transcendental.infinite F B + simp_rw [Algebra.Transcendental.rank_eq_cardinalMk] + rw [sup_def, mul_mk_eq_max, ← Cardinal.lift_le.{u}] + refine (lift_cardinalMk_adjoin_le _ _).trans ?_ + calc + _ ≤ Cardinal.lift.{v} #F ⊔ Cardinal.lift.{u} (#A ⊔ #B) ⊔ ℵ₀ := by + gcongr + rw [Cardinal.lift_le] + exact (mk_union_le _ _).trans_eq (by simp) + _ = _ := by + simp [lift_mk_le_lift_mk_of_injective (algebraMap F A).injective] diff --git a/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean b/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean new file mode 100644 index 0000000000000..db169e8b20d4c --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/TranscendenceBasis.lean @@ -0,0 +1,129 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.FieldTheory.Adjoin +import Mathlib.RingTheory.AlgebraicIndependent.Transcendental + +/-! +# Transcendence basis + +This file defines the transcendence basis as a maximal algebraically independent subset. + +## Main results + +* `exists_isTranscendenceBasis`: a ring extension has a transcendence basis + +## References + +* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) + +## TODO +Define the transcendence degree and show it is independent of the choice of a +transcendence basis. + +## Tags +transcendence basis, transcendence degree, transcendence + +-/ + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +universe u v w + +variable {ι ι' : Type*} (R : Type*) {K A A' : Type*} +variable {x : ι → A} +variable [CommRing R] [CommRing A] [CommRing A'] [Algebra R A] [Algebra R A'] + +open AlgebraicIndependent + +theorem exists_isTranscendenceBasis (h : Injective (algebraMap R A)) : + ∃ s : Set A, IsTranscendenceBasis R ((↑) : s → A) := by + cases' exists_maximal_algebraicIndependent (∅ : Set A) Set.univ (Set.subset_univ _) + ((algebraicIndependent_empty_iff R A).2 h) with + s hs + refine ⟨s, hs.2.1.1, fun t ht hst ↦ ?_⟩ + simp only [Subtype.range_coe_subtype, setOf_mem_eq] at * + exact hs.2.eq_of_le ⟨ht, subset_univ _⟩ hst + +/-- `Type` version of `exists_isTranscendenceBasis`. -/ +theorem exists_isTranscendenceBasis' (R : Type u) {A : Type v} [CommRing R] [CommRing A] + [Algebra R A] (h : Injective (algebraMap R A)) : + ∃ (ι : Type v) (x : ι → A), IsTranscendenceBasis R x := by + obtain ⟨s, h⟩ := exists_isTranscendenceBasis R h + exact ⟨s, Subtype.val, h⟩ + +variable {R} + +theorem AlgebraicIndependent.isTranscendenceBasis_iff {ι : Type w} {R : Type u} [CommRing R] + [Nontrivial R] {A : Type v} [CommRing A] [Algebra R A] {x : ι → A} + (i : AlgebraicIndependent R x) : + IsTranscendenceBasis R x ↔ + ∀ (κ : Type v) (w : κ → A) (_ : AlgebraicIndependent R w) (j : ι → κ) (_ : w ∘ j = x), + Surjective j := by + fconstructor + · rintro p κ w i' j rfl + have p := p.2 (range w) i'.coe_range (range_comp_subset_range _ _) + rw [range_comp, ← @image_univ _ _ w] at p + exact range_eq_univ.mp (image_injective.mpr i'.injective p) + · intro p + use i + intro w i' h + specialize p w ((↑) : w → A) i' (fun i => ⟨x i, range_subset_iff.mp h i⟩) (by ext; simp) + have q := congr_arg (fun s => ((↑) : w → A) '' s) p.range_eq + dsimp at q + rw [← image_univ, image_image] at q + simpa using q + +theorem IsTranscendenceBasis.isAlgebraic [Nontrivial R] (hx : IsTranscendenceBasis R x) : + Algebra.IsAlgebraic (adjoin R (range x)) A := by + constructor + intro a + rw [← not_iff_comm.1 (hx.1.option_iff _).symm] + intro ai + have h₁ : range x ⊆ range fun o : Option ι => o.elim a x := by + rintro x ⟨y, rfl⟩ + exact ⟨some y, rfl⟩ + have h₂ : range x ≠ range fun o : Option ι => o.elim a x := by + intro h + have : a ∈ range x := by + rw [h] + exact ⟨none, rfl⟩ + rcases this with ⟨b, rfl⟩ + have : some b = none := ai.injective rfl + simpa + exact h₂ (hx.2 (Set.range fun o : Option ι => o.elim a x) + ((algebraicIndependent_subtype_range ai.injective).2 ai) h₁) + +/-- If `x` is a transcendence basis of `A/R`, then it is empty if and only if +`A/R` is algebraic. -/ +theorem IsTranscendenceBasis.isEmpty_iff_isAlgebraic [Nontrivial R] + (hx : IsTranscendenceBasis R x) : + IsEmpty ι ↔ Algebra.IsAlgebraic R A := by + refine ⟨fun _ ↦ ?_, fun _ ↦ hx.1.isEmpty_of_isAlgebraic⟩ + have := hx.isAlgebraic + rw [Set.range_eq_empty x, adjoin_empty] at this + exact algebra_isAlgebraic_of_algebra_isAlgebraic_bot_left R A + +/-- If `x` is a transcendence basis of `A/R`, then it is not empty if and only if +`A/R` is transcendental. -/ +theorem IsTranscendenceBasis.nonempty_iff_transcendental [Nontrivial R] + (hx : IsTranscendenceBasis R x) : + Nonempty ι ↔ Algebra.Transcendental R A := by + rw [← not_isEmpty_iff, Algebra.transcendental_iff_not_isAlgebraic, hx.isEmpty_iff_isAlgebraic] + +theorem IsTranscendenceBasis.isAlgebraic_field {F E : Type*} {x : ι → E} + [Field F] [Field E] [Algebra F E] (hx : IsTranscendenceBasis F x) : + Algebra.IsAlgebraic (IntermediateField.adjoin F (range x)) E := by + haveI := hx.isAlgebraic + set S := range x + letI : Algebra (adjoin F S) (IntermediateField.adjoin F S) := + (Subalgebra.inclusion (IntermediateField.algebra_adjoin_le_adjoin F S)).toRingHom.toAlgebra + haveI : IsScalarTower (adjoin F S) (IntermediateField.adjoin F S) E := + IsScalarTower.of_algebraMap_eq (congrFun rfl) + exact Algebra.IsAlgebraic.extendScalars (R := adjoin F S) (Subalgebra.inclusion_injective _) diff --git a/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean b/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean new file mode 100644 index 0000000000000..332493c379080 --- /dev/null +++ b/Mathlib/RingTheory/AlgebraicIndependent/Transcendental.lean @@ -0,0 +1,146 @@ +/- +Copyright (c) 2021 Chris Hughes. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Chris Hughes +-/ +import Mathlib.Data.Fin.Tuple.Reflection +import Mathlib.RingTheory.Algebraic.MvPolynomial +import Mathlib.RingTheory.AlgebraicIndependent.Basic + +/-! +# Algebraic Independence + +This file relates algebraic independence and transcendence (or algebraicity) of elements. + +## References + +* [Stacks: Transcendence](https://stacks.math.columbia.edu/tag/030D) + +## Tags +transcendence + +-/ + +noncomputable section + +open Function Set Subalgebra MvPolynomial Algebra + +open scoped Classical + +variable {ι ι' R K A A' : Type*} {x : ι → A} +variable [CommRing R] [CommRing A] [CommRing A'] [Algebra R A] [Algebra R A'] + +/-- A one-element family `x` is algebraically independent if and only if +its element is transcendental. -/ +@[simp] +theorem algebraicIndependent_unique_type_iff [Unique ι] : + AlgebraicIndependent R x ↔ Transcendental R (x default) := by + rw [transcendental_iff_injective, algebraicIndependent_iff_injective_aeval] + let i := (renameEquiv R (Equiv.equivPUnit.{_, 1} ι)).trans (pUnitAlgEquiv R) + have key : aeval (R := R) x = (Polynomial.aeval (R := R) (x default)).comp i := by + ext y + simp [i, Subsingleton.elim y default] + simp [key] + +/-- The one-element family `![x]` is algebraically independent if and only if +`x` is transcendental. -/ +theorem algebraicIndependent_iff_transcendental {x : A} : + AlgebraicIndependent R ![x] ↔ Transcendental R x := by + simp + +namespace AlgebraicIndependent + +variable (hx : AlgebraicIndependent R x) +include hx + +/-- If a family `x` is algebraically independent, then any of its element is transcendental. -/ +theorem transcendental (i : ι) : Transcendental R (x i) := by + have := hx.comp ![i] (Function.injective_of_subsingleton _) + have : AlgebraicIndependent R ![x i] := by rwa [← FinVec.map_eq] at this + rwa [← algebraicIndependent_iff_transcendental] + +/-- If `A/R` is algebraic, then all algebraically independent families are empty. -/ +theorem isEmpty_of_isAlgebraic [Algebra.IsAlgebraic R A] : IsEmpty ι := by + rcases isEmpty_or_nonempty ι with h | ⟨⟨i⟩⟩ + · exact h + exact False.elim (hx.transcendental i (Algebra.IsAlgebraic.isAlgebraic _)) + +end AlgebraicIndependent + +open AlgebraicIndependent + +theorem AlgebraicIndependent.option_iff (hx : AlgebraicIndependent R x) (a : A) : + (AlgebraicIndependent R fun o : Option ι => o.elim a x) ↔ + Transcendental (adjoin R (Set.range x)) a := by + rw [algebraicIndependent_iff_injective_aeval, transcendental_iff_injective, + ← AlgHom.coe_toRingHom, ← hx.aeval_comp_mvPolynomialOptionEquivPolynomialAdjoin, + RingHom.coe_comp] + exact Injective.of_comp_iff' (Polynomial.aeval a) + (mvPolynomialOptionEquivPolynomialAdjoin hx).bijective + +/-- Variant of `algebraicIndependent_of_finite` using `Transcendental`. -/ +theorem algebraicIndependent_of_finite' (s : Set A) + (hinj : Injective (algebraMap R A)) + (H : ∀ t ⊆ s, t.Finite → ∀ a ∈ s, a ∉ t → Transcendental (adjoin R t) a) : + AlgebraicIndependent R ((↑) : s → A) := by + classical + refine algebraicIndependent_of_finite s fun t hts hfin ↦ hfin.induction_on' + ((algebraicIndependent_empty_iff R A).2 hinj) fun {a} {u} ha hu ha' h ↦ ?_ + convert ((Subtype.range_coe ▸ h.option_iff a).2 <| H u (hu.trans hts) (hfin.subset hu) + a (hts ha) ha').comp _ (Set.subtypeInsertEquivOption ha').injective + ext x + by_cases h : ↑x = a <;> simp [h, Set.subtypeInsertEquivOption] + +/-- `Type` version of `algebraicIndependent_of_finite'`. -/ +theorem algebraicIndependent_of_finite_type' + (hinj : Injective (algebraMap R A)) + (H : ∀ t : Set ι, t.Finite → ∀ i : ι, i ∉ t → Transcendental (adjoin R (x '' t)) (x i)) : + AlgebraicIndependent R x := by + nontriviality R + haveI := hinj.nontrivial + have hx : Injective x := by + simp_rw [Transcendental] at H + contrapose! H + obtain ⟨i, j, h1, h2⟩ := not_injective_iff.1 H + refine ⟨{j}, by simp, i, by simp [h2], ?_⟩ + rw [h1, Set.image_singleton] + exact isAlgebraic_algebraMap (⟨x j, Algebra.self_mem_adjoin_singleton R _⟩ : adjoin R {x j}) + rw [← Set.coe_comp_rangeFactorization x] + refine .comp (algebraicIndependent_of_finite' _ hinj fun t ht hfin a ha ha' ↦ ?_) _ + (Set.rightInverse_rangeSplitting hx).injective + change Finite t at hfin + have := H (x ⁻¹' t) (Finite.of_injective _ (hx.restrictPreimage t)) + ((Equiv.ofInjective _ hx).symm ⟨_, ha⟩) + (by rwa [Set.mem_preimage, Equiv.apply_ofInjective_symm hx]) + rwa [Set.image_preimage_eq_inter_range, Set.inter_eq_self_of_subset_left ht, + Equiv.apply_ofInjective_symm hx] at this + +namespace MvPolynomial + +/-- If for each `i : ι`, `f_i : R[X]` is transcendental over `R`, then `{f_i(X_i) | i : ι}` +in `MvPolynomial ι R` is algebraically independent over `R`. -/ +theorem algebraicIndependent_polynomial_aeval_X + (f : ι → Polynomial R) (hf : ∀ i, Transcendental R (f i)) : + AlgebraicIndependent R fun i ↦ Polynomial.aeval (X i : MvPolynomial ι R) (f i) := by + set x := fun i ↦ Polynomial.aeval (X i : MvPolynomial ι R) (f i) + refine algebraicIndependent_of_finite_type' (C_injective _ _) fun t _ i hi ↦ ?_ + have hle : adjoin R (x '' t) ≤ supported R t := by + rw [Algebra.adjoin_le_iff, Set.image_subset_iff] + intro _ h + rw [Set.mem_preimage] + refine Algebra.adjoin_mono ?_ (Polynomial.aeval_mem_adjoin_singleton R _) + simp_rw [singleton_subset_iff, Set.mem_image_of_mem _ h] + exact (transcendental_supported_polynomial_aeval_X R hi (hf i)).of_tower_top_of_subalgebra_le hle + +end MvPolynomial + +/-- If `{x_i : A | i : ι}` is algebraically independent over `R`, and for each `i`, +`f_i : R[X]` is transcendental over `R`, then `{f_i(x_i) | i : ι}` is also +algebraically independent over `R`. -/ +theorem AlgebraicIndependent.polynomial_aeval_of_transcendental + (hx : AlgebraicIndependent R x) + {f : ι → Polynomial R} (hf : ∀ i, Transcendental R (f i)) : + AlgebraicIndependent R fun i ↦ Polynomial.aeval (x i) (f i) := by + convert aeval_of_algebraicIndependent hx (algebraicIndependent_polynomial_aeval_X _ hf) + rw [← AlgHom.comp_apply] + congr 1; ext1; simp diff --git a/Mathlib/RingTheory/Artinian.lean b/Mathlib/RingTheory/Artinian.lean index 2911d10aa8bb9..6bf257f5cca5f 100644 --- a/Mathlib/RingTheory/Artinian.lean +++ b/Mathlib/RingTheory/Artinian.lean @@ -11,6 +11,8 @@ import Mathlib.RingTheory.Nakayama import Mathlib.RingTheory.SimpleModule import Mathlib.Tactic.RSuffices import Mathlib.Tactic.StacksAttribute +import Mathlib.RingTheory.LocalRing.Basic +import Mathlib.RingTheory.Nilpotent.Lemmas /-! # Artinian rings and modules diff --git a/Mathlib/RingTheory/Binomial.lean b/Mathlib/RingTheory/Binomial.lean index ad5a0893a9a04..dc1ee22987949 100644 --- a/Mathlib/RingTheory/Binomial.lean +++ b/Mathlib/RingTheory/Binomial.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Scott Carnahan -/ import Mathlib.Algebra.Polynomial.Smeval -import Mathlib.Algebra.Order.Floor import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.RingTheory.Polynomial.Pochhammer import Mathlib.Tactic.FieldSimp @@ -67,7 +66,7 @@ number powers, but retain the ring name. We introduce `Ring.multichoose` as the quotient. -/ class BinomialRing (R : Type*) [AddCommMonoid R] [Pow R ℕ] where /-- Scalar multiplication by positive integers is injective -/ - nsmul_right_injective (n : ℕ) (h : n ≠ 0) : Injective (n • · : R → R) + nsmul_right_injective {n : ℕ} (h : n ≠ 0) : Injective (n • · : R → R) /-- A multichoose function, giving the quotient of Pochhammer evaluations by factorials. -/ multichoose : R → ℕ → R /-- The `n`th ascending Pochhammer polynomial evaluated at any element is divisible by `n!` -/ @@ -78,8 +77,8 @@ namespace Ring variable {R : Type*} [AddCommMonoid R] [Pow R ℕ] [BinomialRing R] -theorem nsmul_right_injective (n : ℕ) (h : n ≠ 0) : - Injective (n • · : R → R) := BinomialRing.nsmul_right_injective n h +theorem nsmul_right_injective {n : ℕ} (h : n ≠ 0) : + Injective (n • · : R → R) := BinomialRing.nsmul_right_injective h /-- The multichoose function is the quotient of ascending Pochhammer evaluation by the corresponding factorial. When applied to natural numbers, `multichoose k n` describes choosing a multiset of `n` @@ -96,7 +95,7 @@ theorem factorial_nsmul_multichoose_eq_ascPochhammer (r : R) (n : ℕ) : @[simp] theorem multichoose_zero_right' (r : R) : multichoose r 0 = r ^ 0 := by - refine nsmul_right_injective (Nat.factorial 0) (Nat.factorial_ne_zero 0) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero 0) ?_ simp only rw [factorial_nsmul_multichoose_eq_ascPochhammer, ascPochhammer_zero, smeval_one, Nat.factorial] @@ -106,7 +105,7 @@ theorem multichoose_zero_right [MulOneClass R] [NatPowAssoc R] @[simp] theorem multichoose_one_right' (r : R) : multichoose r 1 = r ^ 1 := by - refine nsmul_right_injective (Nat.factorial 1) (Nat.factorial_ne_zero 1) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero 1) ?_ simp only rw [factorial_nsmul_multichoose_eq_ascPochhammer, ascPochhammer_one, smeval_X, Nat.factorial_one, one_smul] @@ -118,7 +117,7 @@ variable {R : Type*} [NonAssocSemiring R] [Pow R ℕ] [NatPowAssoc R] [BinomialR @[simp] theorem multichoose_zero_succ (k : ℕ) : multichoose (0 : R) (k + 1) = 0 := by - refine nsmul_right_injective (Nat.factorial (k + 1)) (Nat.factorial_ne_zero (k + 1)) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero (k + 1)) ?_ simp only rw [factorial_nsmul_multichoose_eq_ascPochhammer, smul_zero, ascPochhammer_succ_left, smeval_X_mul, zero_mul] @@ -127,7 +126,7 @@ theorem ascPochhammer_succ_succ (r : R) (k : ℕ) : smeval (ascPochhammer ℕ (k + 1)) (r + 1) = Nat.factorial (k + 1) • multichoose (r + 1) k + smeval (ascPochhammer ℕ (k + 1)) r := by nth_rw 1 [ascPochhammer_succ_right, ascPochhammer_succ_left, mul_comm (ascPochhammer ℕ k)] - simp only [smeval_mul, smeval_comp ℕ _ _ r, smeval_add, smeval_X] + simp only [smeval_mul, smeval_comp, smeval_add, smeval_X] rw [Nat.factorial, mul_smul, factorial_nsmul_multichoose_eq_ascPochhammer] simp only [smeval_one, npow_one, npow_zero, one_smul] rw [← C_eq_natCast, smeval_C, npow_zero, add_assoc, add_mul, add_comm 1, @nsmul_one, add_mul] @@ -136,7 +135,7 @@ theorem ascPochhammer_succ_succ (r : R) (k : ℕ) : theorem multichoose_succ_succ (r : R) (k : ℕ) : multichoose (r + 1) (k + 1) = multichoose r (k + 1) + multichoose (r + 1) k := by - refine nsmul_right_injective (Nat.factorial (k + 1)) (Nat.factorial_ne_zero (k + 1)) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero (k + 1)) ?_ simp only [factorial_nsmul_multichoose_eq_ascPochhammer, smul_add] rw [add_comm (smeval (ascPochhammer ℕ (k+1)) r), ascPochhammer_succ_succ r k] @@ -225,10 +224,10 @@ section Basic_Instances open Polynomial instance Nat.instBinomialRing : BinomialRing ℕ where - nsmul_right_injective _ hn _ _ hrs := Nat.eq_of_mul_eq_mul_left (Nat.pos_of_ne_zero hn) hrs - multichoose n k := Nat.choose (n + k - 1) k + nsmul_right_injective hn _ _ hrs := Nat.eq_of_mul_eq_mul_left (Nat.pos_of_ne_zero hn) hrs + multichoose := Nat.multichoose factorial_nsmul_multichoose r n := by - rw [smul_eq_mul, ← Nat.descFactorial_eq_factorial_mul_choose, + rw [smul_eq_mul, Nat.multichoose_eq r n, ← Nat.descFactorial_eq_factorial_mul_choose, ← eval_eq_smeval r (ascPochhammer ℕ n), ascPochhammer_nat_eq_descFactorial] /-- The multichoose function for integers. -/ @@ -238,7 +237,7 @@ def Int.multichoose (n : ℤ) (k : ℕ) : ℤ := | negSucc n => (-1) ^ k * Nat.choose (n + 1) k instance Int.instBinomialRing : BinomialRing ℤ where - nsmul_right_injective _ hn _ _ hrs := Int.eq_of_mul_eq_mul_left (Int.ofNat_ne_zero.mpr hn) hrs + nsmul_right_injective hn _ _ hrs := Int.eq_of_mul_eq_mul_left (Int.ofNat_ne_zero.mpr hn) hrs multichoose := Int.multichoose factorial_nsmul_multichoose r k := by rw [Int.multichoose.eq_def, nsmul_eq_mul] @@ -254,7 +253,7 @@ instance Int.instBinomialRing : BinomialRing ℤ where ← Int.neg_ofNat_succ, ascPochhammer_smeval_neg_eq_descPochhammer] noncomputable instance {R : Type*} [AddCommMonoid R] [Module ℚ≥0 R] [Pow R ℕ] : BinomialRing R where - nsmul_right_injective n hn r s hrs := by + nsmul_right_injective {n} hn r s hrs := by rw [← one_smul ℚ≥0 r, ← one_smul ℚ≥0 s, show 1 = (n : ℚ≥0)⁻¹ • (n : ℚ≥0) by simp_all] simp_all only [smul_assoc, Nat.cast_smul_eq_nsmul] multichoose r n := (n.factorial : ℚ≥0)⁻¹ • Polynomial.smeval (ascPochhammer ℕ n) r @@ -309,7 +308,7 @@ theorem smeval_ascPochhammer_nat_cast {R} [NonAssocRing R] [Pow R ℕ] [NatPowAs rw [smeval_at_natCast (ascPochhammer ℕ k) n] theorem multichoose_neg_self (n : ℕ) : multichoose (-n : ℤ) n = (-1)^n := by - apply nsmul_right_injective _ (Nat.factorial_ne_zero _) + apply nsmul_right_injective (Nat.factorial_ne_zero _) on_goal 1 => simp only -- This closes both remaining goals at once. rw [factorial_nsmul_multichoose_eq_ascPochhammer, smeval_ascPochhammer_self_neg, nsmul_eq_mul, @@ -317,25 +316,25 @@ theorem multichoose_neg_self (n : ℕ) : multichoose (-n : ℤ) n = (-1)^n := by @[simp] theorem multichoose_neg_succ (n : ℕ) : multichoose (-n : ℤ) (n + 1) = 0 := by - apply nsmul_right_injective _ (Nat.factorial_ne_zero _) + apply nsmul_right_injective (Nat.factorial_ne_zero _) on_goal 1 => simp only -- This closes both remaining goals at once. rw [factorial_nsmul_multichoose_eq_ascPochhammer, smeval_ascPochhammer_succ_neg, smul_zero] theorem multichoose_neg_add (n k : ℕ) : multichoose (-n : ℤ) (n + k + 1) = 0 := by - refine nsmul_right_injective (Nat.factorial (n + k + 1)) (Nat.factorial_ne_zero (n + k + 1)) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero (n + k + 1)) ?_ simp only rw [factorial_nsmul_multichoose_eq_ascPochhammer, smeval_ascPochhammer_neg_add, smul_zero] @[simp] theorem multichoose_neg_of_lt (n k : ℕ) (h : n < k) : multichoose (-n : ℤ) k = 0 := by - refine nsmul_right_injective (Nat.factorial k) (Nat.factorial_ne_zero k) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero k) ?_ simp only rw [factorial_nsmul_multichoose_eq_ascPochhammer, smeval_ascPochhammer_neg_of_lt h, smul_zero] theorem multichoose_succ_neg_natCast [NatPowAssoc R] (n : ℕ) : multichoose (-n : R) (n + 1) = 0 := by - refine nsmul_right_injective (Nat.factorial (n + 1)) (Nat.factorial_ne_zero (n + 1)) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero (n + 1)) ?_ simp only [smul_zero] rw [factorial_nsmul_multichoose_eq_ascPochhammer, smeval_neg_nat, smeval_ascPochhammer_succ_neg n, Int.cast_zero] @@ -381,7 +380,7 @@ theorem descPochhammer_eq_factorial_smul_choose [NatPowAssoc R] (r : R) (n : ℕ rw [h, ascPochhammer_smeval_cast, add_comm_sub] theorem choose_natCast [NatPowAssoc R] (n k : ℕ) : choose (n : R) k = Nat.choose n k := by - refine nsmul_right_injective (Nat.factorial k) (Nat.factorial_ne_zero k) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero k) ?_ simp only rw [← descPochhammer_eq_factorial_smul_choose, nsmul_eq_mul, ← Nat.cast_mul, ← Nat.descFactorial_eq_factorial_mul_choose, ← descPochhammer_smeval_eq_descFactorial] @@ -392,7 +391,7 @@ alias choose_nat_cast := choose_natCast @[simp] theorem choose_zero_right' (r : R) : choose r 0 = (r + 1) ^ 0 := by dsimp only [choose] - refine nsmul_right_injective (Nat.factorial 0) (Nat.factorial_ne_zero 0) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero 0) ?_ simp [factorial_nsmul_multichoose_eq_ascPochhammer] theorem choose_zero_right [NatPowAssoc R] (r : R) : choose r 0 = 1 := by @@ -425,15 +424,15 @@ theorem descPochhammer_succ_succ_smeval {R} [NonAssocRing R] [Pow R ℕ] [NatPow (k + 1) • smeval (descPochhammer ℤ k) r + smeval (descPochhammer ℤ (k + 1)) r := by nth_rw 1 [descPochhammer_succ_left] rw [descPochhammer_succ_right, mul_comm (descPochhammer ℤ k)] - simp only [smeval_comp ℤ _ _ (r + 1), smeval_sub, smeval_add, smeval_mul, smeval_X, smeval_one, - npow_one, npow_zero, one_smul, add_sub_cancel_right, sub_mul, add_mul, add_smul, one_mul] + simp only [smeval_comp, smeval_sub, smeval_add, smeval_mul, smeval_X, smeval_one, npow_one, + npow_zero, one_smul, add_sub_cancel_right, sub_mul, add_mul, add_smul, one_mul] rw [← C_eq_natCast, smeval_C, npow_zero, add_comm (k • smeval (descPochhammer ℤ k) r) _, add_assoc, add_comm (k • smeval (descPochhammer ℤ k) r) _, ← add_assoc, ← add_sub_assoc, nsmul_eq_mul, zsmul_one, Int.cast_natCast, sub_add_cancel, add_comm] theorem choose_succ_succ [NatPowAssoc R] (r : R) (k : ℕ) : choose (r + 1) (k + 1) = choose r k + choose r (k + 1) := by - refine nsmul_right_injective (Nat.factorial (k + 1)) (Nat.factorial_ne_zero (k + 1)) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero (k + 1)) ?_ simp only [smul_add, ← descPochhammer_eq_factorial_smul_choose] rw [Nat.factorial_succ, mul_smul, ← descPochhammer_eq_factorial_smul_choose r, descPochhammer_succ_succ_smeval r k] @@ -447,9 +446,9 @@ theorem choose_eq_nat_choose [NatPowAssoc R] (n k : ℕ) : choose (n : R) k = Na | zero => rw [choose_zero_right, Nat.choose_zero_right, Nat.cast_one] | succ k => rw [Nat.cast_succ, choose_succ_succ, ih, ih, Nat.choose_succ_succ, Nat.cast_add] -theorem choose_smul_choose [NatPowAssoc R] (r : R) (n k : ℕ) (hkn : k ≤ n) : +theorem choose_smul_choose [NatPowAssoc R] (r : R) {n k : ℕ} (hkn : k ≤ n) : (Nat.choose n k) • choose r n = choose r k * choose (r - k) (n - k) := by - refine nsmul_right_injective (Nat.factorial n) (Nat.factorial_ne_zero n) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero n) ?_ simp only rw [nsmul_left_comm, ← descPochhammer_eq_factorial_smul_choose, ← Nat.choose_mul_factorial_mul_factorial hkn, ← smul_mul_smul_comm, @@ -461,7 +460,7 @@ theorem choose_smul_choose [NatPowAssoc R] (r : R) (n k : ℕ) (hkn : k ≤ n) : theorem choose_add_smul_choose [NatPowAssoc R] (r : R) (n k : ℕ) : (Nat.choose (n + k) k) • choose (r + k) (n + k) = choose (r + k) k * choose r n := by - rw [choose_smul_choose (r + k) (n + k) k (Nat.le_add_left k n), Nat.add_sub_cancel, + rw [choose_smul_choose (r + k) (Nat.le_add_left k n), Nat.add_sub_cancel, add_sub_cancel_right] end @@ -501,7 +500,7 @@ theorem descPochhammer_smeval_add [Ring R] {r s : R} (k : ℕ) (h: Commute r s) theorem add_choose_eq [Ring R] [BinomialRing R] {r s : R} (k : ℕ) (h : Commute r s) : choose (r + s) k = ∑ ij ∈ antidiagonal k, choose r ij.1 * choose s ij.2 := by - refine nsmul_right_injective (Nat.factorial k) (Nat.factorial_ne_zero k) ?_ + refine nsmul_right_injective (Nat.factorial_ne_zero k) ?_ simp only rw [← descPochhammer_eq_factorial_smul_choose, smul_sum, descPochhammer_smeval_add _ h] refine sum_congr rfl ?_ diff --git a/Mathlib/RingTheory/ChainOfDivisors.lean b/Mathlib/RingTheory/ChainOfDivisors.lean index a1921d9752ce6..68af812321e63 100644 --- a/Mathlib/RingTheory/ChainOfDivisors.lean +++ b/Mathlib/RingTheory/ChainOfDivisors.lean @@ -5,7 +5,7 @@ Authors: Anne Baanen, Paul Lezeau -/ import Mathlib.Algebra.GCDMonoid.Basic import Mathlib.Algebra.IsPrimePow -import Mathlib.Algebra.Squarefree.Basic +import Mathlib.RingTheory.UniqueFactorizationDomain.Multiplicity import Mathlib.Data.ZMod.Defs import Mathlib.Order.Atoms import Mathlib.Order.Hom.Bounded @@ -58,7 +58,7 @@ theorem Associates.isAtom_iff {p : Associates M} (h₁ : p ≠ 0) : IsAtom p ↔ ⟨(ha.unit⁻¹ : Units _), by rw [hab, mul_assoc, IsUnit.mul_val_inv ha, mul_one]⟩) hb⟩⟩ -open UniqueFactorizationMonoid multiplicity Irreducible Associates +open UniqueFactorizationMonoid Irreducible Associates namespace DivisorChain @@ -311,8 +311,8 @@ theorem emultiplicity_prime_le_emultiplicity_image_by_factor_orderIso {m p : Ass · simp [hn] by_cases hm : m = 0 · simp [hm] at hp - rw [(finite_prime_left (prime_of_normalized_factor p hp) hm).emultiplicity_eq_multiplicity, - ← pow_dvd_iff_le_emultiplicity] + rw [FiniteMultiplicity.of_prime_left (prime_of_normalized_factor p hp) hm + |>.emultiplicity_eq_multiplicity, ← pow_dvd_iff_le_emultiplicity] apply pow_image_of_prime_by_factor_orderIso_dvd hn hp d (pow_multiplicity_dvd ..) theorem emultiplicity_prime_eq_emultiplicity_image_by_factor_orderIso {m p : Associates M} diff --git a/Mathlib/RingTheory/Coalgebra/TensorProduct.lean b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean index c7ac28b39f0ee..dafc8270e1007 100644 --- a/Mathlib/RingTheory/Coalgebra/TensorProduct.lean +++ b/Mathlib/RingTheory/Coalgebra/TensorProduct.lean @@ -57,8 +57,8 @@ noncomputable instance TensorProduct.instCoalgebra : Coalgebra R (M ⊗[R] N) := map_comp_comul := by rw [CoalgebraCat.ofComonObjCoalgebraStruct_comul] simp [-Mon_.monMonoidalStruct_tensorObj_X, - ModuleCat.MonoidalCategory.instMonoidalCategoryStruct_tensorHom, - ModuleCat.comp_def, ModuleCat.of, ModuleCat.asHom, + ModuleCat.MonoidalCategory.instMonoidalCategoryStruct_tensorHom_hom, + ModuleCat.hom_comp, ModuleCat.of, ModuleCat.ofHom, ModuleCat.MonoidalCategory.tensorμ_eq_tensorTensorTensorComm] } end diff --git a/Mathlib/RingTheory/Coprime/Basic.lean b/Mathlib/RingTheory/Coprime/Basic.lean index 851c87915e7a1..0e608f5a7df62 100644 --- a/Mathlib/RingTheory/Coprime/Basic.lean +++ b/Mathlib/RingTheory/Coprime/Basic.lean @@ -244,7 +244,7 @@ end ScalarTower section CommSemiringUnit -variable {R : Type*} [CommSemiring R] {x : R} +variable {R : Type*} [CommSemiring R] {x u v : R} theorem isCoprime_mul_unit_left_left (hu : IsUnit x) (y z : R) : IsCoprime (x * y) z ↔ IsCoprime y z := @@ -256,10 +256,6 @@ theorem isCoprime_mul_unit_left_right (hu : IsUnit x) (y z : R) : let ⟨u, hu⟩ := hu hu ▸ isCoprime_group_smul_right u y z -theorem isCoprime_mul_unit_left (hu : IsUnit x) (y z : R) : - IsCoprime (x * y) (x * z) ↔ IsCoprime y z := - (isCoprime_mul_unit_left_left hu y (x * z)).trans (isCoprime_mul_unit_left_right hu y z) - theorem isCoprime_mul_unit_right_left (hu : IsUnit x) (y z : R) : IsCoprime (y * x) z ↔ IsCoprime y z := mul_comm x y ▸ isCoprime_mul_unit_left_left hu y z @@ -268,9 +264,25 @@ theorem isCoprime_mul_unit_right_right (hu : IsUnit x) (y z : R) : IsCoprime y (z * x) ↔ IsCoprime y z := mul_comm x z ▸ isCoprime_mul_unit_left_right hu y z +theorem isCoprime_mul_units_left (hu : IsUnit u) (hv : IsUnit v) (y z : R) : + IsCoprime (u * y) (v * z) ↔ IsCoprime y z := + Iff.trans + (isCoprime_mul_unit_left_left hu _ _) + (isCoprime_mul_unit_left_right hv _ _) + +theorem isCoprime_mul_units_right (hu : IsUnit u) (hv : IsUnit v) (y z : R) : + IsCoprime (y * u) (z * v) ↔ IsCoprime y z := + Iff.trans + (isCoprime_mul_unit_right_left hu _ _) + (isCoprime_mul_unit_right_right hv _ _) + +theorem isCoprime_mul_unit_left (hu : IsUnit x) (y z : R) : + IsCoprime (x * y) (x * z) ↔ IsCoprime y z := + isCoprime_mul_units_left hu hu _ _ + theorem isCoprime_mul_unit_right (hu : IsUnit x) (y z : R) : IsCoprime (y * x) (z * x) ↔ IsCoprime y z := - (isCoprime_mul_unit_right_left hu y (z * x)).trans (isCoprime_mul_unit_right_right hu y z) + isCoprime_mul_units_right hu hu _ _ end CommSemiringUnit diff --git a/Mathlib/RingTheory/DedekindDomain/Different.lean b/Mathlib/RingTheory/DedekindDomain/Different.lean index bbc06fe1ddaf3..be9c17f20d9c5 100644 --- a/Mathlib/RingTheory/DedekindDomain/Different.lean +++ b/Mathlib/RingTheory/DedekindDomain/Different.lean @@ -188,7 +188,7 @@ lemma isIntegral_discr_mul_of_mem_traceDual rw [cramer_apply] apply IsIntegral.det intros j k - rw [updateColumn_apply] + rw [updateCol_apply] split · rw [mul_assoc] rw [mem_traceDual_iff_isIntegral] at hx diff --git a/Mathlib/RingTheory/DedekindDomain/Ideal.lean b/Mathlib/RingTheory/DedekindDomain/Ideal.lean index 2533459ec4771..8ad308eb008d5 100644 --- a/Mathlib/RingTheory/DedekindDomain/Ideal.lean +++ b/Mathlib/RingTheory/DedekindDomain/Ideal.lean @@ -9,6 +9,7 @@ import Mathlib.RingTheory.MaximalSpectrum import Mathlib.RingTheory.ChainOfDivisors import Mathlib.RingTheory.DedekindDomain.Basic import Mathlib.RingTheory.FractionalIdeal.Operations +import Mathlib.Algebra.Squarefree.Basic /-! # Dedekind domains and ideals @@ -911,7 +912,7 @@ theorem irreducible_pow_sup_of_ge (hI : I ≠ ⊥) (hJ : Irreducible J) (n : ℕ classical rw [irreducible_pow_sup hI hJ, min_eq_left] · congr - rw [← Nat.cast_inj (R := ℕ∞), ← multiplicity.Finite.emultiplicity_eq_multiplicity, + rw [← Nat.cast_inj (R := ℕ∞), ← FiniteMultiplicity.emultiplicity_eq_multiplicity, emultiplicity_eq_count_normalizedFactors hJ hI, normalize_eq J] rw [← emultiplicity_lt_top] apply hn.trans_lt @@ -1317,7 +1318,7 @@ end ChineseRemainder section PID -open multiplicity UniqueFactorizationMonoid Ideal +open UniqueFactorizationMonoid Ideal variable {R} variable [IsDomain R] [IsPrincipalIdealRing R] @@ -1358,18 +1359,18 @@ theorem singleton_span_mem_normalizedFactors_of_mem_normalizedFactors [Normaliza theorem emultiplicity_eq_emultiplicity_span {a b : R} : emultiplicity (Ideal.span {a}) (Ideal.span ({b} : Set R)) = emultiplicity a b := by - by_cases h : Finite a b + by_cases h : FiniteMultiplicity a b · rw [h.emultiplicity_eq_multiplicity] apply emultiplicity_eq_of_dvd_of_not_dvd <;> rw [Ideal.span_singleton_pow, span_singleton_dvd_span_singleton_iff_dvd] · exact pow_multiplicity_dvd a b · apply h.not_pow_dvd_of_multiplicity_lt apply lt_add_one - · suffices ¬Finite (Ideal.span ({a} : Set R)) (Ideal.span ({b} : Set R)) by + · suffices ¬FiniteMultiplicity (Ideal.span ({a} : Set R)) (Ideal.span ({b} : Set R)) by rw [emultiplicity_eq_top.2 h, emultiplicity_eq_top.2 this] - exact Finite.not_iff_forall.mpr fun n => by + exact FiniteMultiplicity.not_iff_forall.mpr fun n => by rw [Ideal.span_singleton_pow, span_singleton_dvd_span_singleton_iff_dvd] - exact Finite.not_iff_forall.mp h n + exact FiniteMultiplicity.not_iff_forall.mp h n section NormalizationMonoid variable [NormalizationMonoid R] diff --git a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean index f38e19b607e41..22c54ebc36736 100644 --- a/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean +++ b/Mathlib/RingTheory/DedekindDomain/IntegralClosure.lean @@ -112,25 +112,11 @@ 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 ≠ (0 : A), ∀ x ∈ s, IsIntegral A (y • x) := by - haveI := Classical.decEq L - refine s.induction ?_ ?_ - · use 1, one_ne_zero - rintro x ⟨⟩ - · rintro x s hx ⟨y, hy, hs⟩ - have := exists_integral_multiple - ((IsFractionRing.isAlgebraic_iff A K L).mpr (.of_finite _ x)) - ((injective_iff_map_eq_zero (algebraMap A L)).mp ?_) - · rcases this with ⟨x', y', hy', hx'⟩ - refine ⟨y * y', mul_ne_zero hy hy', fun x'' hx'' => ?_⟩ - rcases Finset.mem_insert.mp hx'' with (rfl | hx'') - · rw [mul_smul, Algebra.smul_def, Algebra.smul_def, mul_comm _ x'', hx'] - exact isIntegral_algebraMap.mul x'.2 - · rw [mul_comm, mul_smul, Algebra.smul_def] - exact isIntegral_algebraMap.mul (hs _ hx'') - · rw [IsScalarTower.algebraMap_eq A K L] - apply (algebraMap K L).injective.comp - exact IsFractionRing.injective _ _ + ∃ y ≠ (0 : A), ∀ x ∈ s, IsIntegral A (y • x) := + have := IsLocalization.isAlgebraic K (nonZeroDivisors A) + have := Algebra.IsAlgebraic.trans' A (algebraMap K L).injective + Algebra.IsAlgebraic.exists_integral_multiples (IsScalarTower.algebraMap_eq A K L ▸ + (algebraMap K L).injective.comp (IsFractionRing.injective _ _)) _ variable (L) diff --git a/Mathlib/RingTheory/DedekindDomain/PID.lean b/Mathlib/RingTheory/DedekindDomain/PID.lean index 69bf559e5c7f8..673e136d6943e 100644 --- a/Mathlib/RingTheory/DedekindDomain/PID.lean +++ b/Mathlib/RingTheory/DedekindDomain/PID.lean @@ -110,7 +110,7 @@ theorem FractionalIdeal.isPrincipal.of_finite_maximals_of_inv {A : Type*} [CommR let s := hf.toFinset haveI := Classical.decEq (Ideal R) have coprime : ∀ M ∈ s, ∀ M' ∈ s.erase M, M ⊔ M' = ⊤ := by - simp_rw [Finset.mem_erase, hf.mem_toFinset] + simp_rw [s, Finset.mem_erase, hf.mem_toFinset] rintro M hM M' ⟨hne, hM'⟩ exact Ideal.IsMaximal.coprime_of_ne hM hM' hne.symm have nle : ∀ M ∈ s, ¬⨅ M' ∈ s.erase M, M' ≤ M := fun M hM => diff --git a/Mathlib/RingTheory/Discriminant.lean b/Mathlib/RingTheory/Discriminant.lean index f3faffa03b668..cd0db7dd94243 100644 --- a/Mathlib/RingTheory/Discriminant.lean +++ b/Mathlib/RingTheory/Discriminant.lean @@ -288,9 +288,9 @@ theorem discr_mul_isIntegral_mem_adjoin [Algebra.IsSeparable K L] [IsIntegrallyC refine Subalgebra.sum_mem _ fun σ _ => Subalgebra.zsmul_mem _ (Subalgebra.prod_mem _ fun j _ => ?_) _ by_cases hji : j = i - · simp only [updateColumn_apply, hji, eq_self_iff_true, PowerBasis.coe_basis] + · simp only [updateCol_apply, hji, eq_self_iff_true, PowerBasis.coe_basis] exact mem_bot.2 (IsIntegrallyClosed.isIntegral_iff.1 <| isIntegral_trace (hz.mul <| hint.pow _)) - · simp only [updateColumn_apply, hji, PowerBasis.coe_basis] + · simp only [updateCol_apply, hji, PowerBasis.coe_basis] exact mem_bot.2 (IsIntegrallyClosed.isIntegral_iff.1 <| isIntegral_trace <| (hint.pow _).mul (hint.pow _)) diff --git a/Mathlib/RingTheory/EisensteinCriterion.lean b/Mathlib/RingTheory/EisensteinCriterion.lean index 0e246b9233e41..775daf2ac12dd 100644 --- a/Mathlib/RingTheory/EisensteinCriterion.lean +++ b/Mathlib/RingTheory/EisensteinCriterion.lean @@ -40,7 +40,7 @@ theorem map_eq_C_mul_X_pow_of_forall_coeff_mem {f : R[X]} {P : Ideal R} · rw [coeff_eq_zero_of_degree_lt, coeff_eq_zero_of_degree_lt] · refine lt_of_le_of_lt (degree_C_mul_X_pow_le _ _) ?_ rwa [← degree_eq_natDegree hf0] - · exact lt_of_le_of_lt (degree_map_le _ _) h + · exact lt_of_le_of_lt degree_map_le h theorem le_natDegree_of_map_eq_mul_X_pow {n : ℕ} {P : Ideal R} (hP : P.IsPrime) {q : R[X]} {c : Polynomial (R ⧸ P)} (hq : map (mk P) q = c * X ^ n) (hc0 : c.degree = 0) : @@ -49,7 +49,7 @@ theorem le_natDegree_of_map_eq_mul_X_pow {n : ℕ} {P : Ideal R} (hP : P.IsPrime (calc ↑n = degree (q.map (mk P)) := by rw [hq, degree_mul, hc0, zero_add, degree_pow, degree_X, nsmul_one] - _ ≤ degree q := degree_map_le _ _ + _ ≤ degree q := degree_map_le _ ≤ natDegree q := degree_le_natDegree ) diff --git a/Mathlib/RingTheory/Filtration.lean b/Mathlib/RingTheory/Filtration.lean index 49f369df496ee..ea599e0713283 100644 --- a/Mathlib/RingTheory/Filtration.lean +++ b/Mathlib/RingTheory/Filtration.lean @@ -40,10 +40,7 @@ This file contains the definitions and basic results around (stable) `I`-filtrat -/ - -universe u v - -variable {R M : Type u} [CommRing R] [AddCommGroup M] [Module R M] (I : Ideal R) +variable {R M : Type*} [CommRing R] [AddCommGroup M] [Module R M] (I : Ideal R) open Polynomial @@ -52,7 +49,7 @@ open scoped Polynomial /-- An `I`-filtration on the module `M` is a sequence of decreasing submodules `N i` such that `I • (N i) ≤ N (i + 1)`. Note that we do not require the filtration to start from `⊤`. -/ @[ext] -structure Ideal.Filtration (M : Type u) [AddCommGroup M] [Module R M] where +structure Ideal.Filtration (M : Type*) [AddCommGroup M] [Module R M] where N : ℕ → Submodule R M mono : ∀ i, N (i + 1) ≤ N i smul_le : ∀ i, I • N i ≤ N (i + 1) diff --git a/Mathlib/RingTheory/FiniteType.lean b/Mathlib/RingTheory/FiniteType.lean index e8cd7c64fe86f..40f8bd11de976 100644 --- a/Mathlib/RingTheory/FiniteType.lean +++ b/Mathlib/RingTheory/FiniteType.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johan Commelin -/ import Mathlib.Algebra.FreeAlgebra +import Mathlib.RingTheory.Adjoin.Polynomial import Mathlib.RingTheory.Adjoin.Tower import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Noetherian.Orzech diff --git a/Mathlib/RingTheory/Finiteness/Defs.lean b/Mathlib/RingTheory/Finiteness/Defs.lean index a56606fa8c8e9..fd8c45bb0be8d 100644 --- a/Mathlib/RingTheory/Finiteness/Defs.lean +++ b/Mathlib/RingTheory/Finiteness/Defs.lean @@ -5,6 +5,7 @@ Authors: Johan Commelin -/ import Mathlib.Algebra.Algebra.Hom import Mathlib.Data.Set.Finite.Lemmas +import Mathlib.Data.Finsupp.Defs import Mathlib.GroupTheory.Finiteness import Mathlib.RingTheory.Ideal.Span import Mathlib.Tactic.Algebraize diff --git a/Mathlib/RingTheory/Flat/Algebra.lean b/Mathlib/RingTheory/Flat/Algebra.lean deleted file mode 100644 index bf379a8806436..0000000000000 --- a/Mathlib/RingTheory/Flat/Algebra.lean +++ /dev/null @@ -1,85 +0,0 @@ -/- -Copyright (c) 2024 Christian Merten. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Christian Merten --/ -import Mathlib.RingTheory.Flat.Stability -import Mathlib.LinearAlgebra.TensorProduct.Tower - -/-! -# Flat algebras and flat ring homomorphisms - -We define flat algebras and flat ring homomorphisms. - -## Main definitions - -* `Algebra.Flat`: an `R`-algebra `S` is flat if it is flat as `R`-module -* `RingHom.Flat`: a ring homomorphism `f : R → S` is flat, if it makes `S` into a flat `R`-algebra - --/ - -universe u v w t - -open Function (Injective Surjective) - -open LinearMap (lsmul rTensor lTensor) - -open TensorProduct - -/-- An `R`-algebra `S` is flat if it is flat as `R`-module. -/ -class Algebra.Flat (R : Type u) (S : Type v) [CommRing R] [CommRing S] [Algebra R S] : Prop where - out : Module.Flat R S - -namespace Algebra.Flat - -attribute [instance] out - -instance self (R : Type u) [CommRing R] : Algebra.Flat R R where - out := Module.Flat.self R - -variable (R : Type u) (S : Type v) [CommRing R] [CommRing S] - -/-- If `T` is a flat `S`-algebra and `S` is a flat `R`-algebra, -then `T` is a flat `R`-algebra. -/ -theorem trans (T : Type w) [CommRing T] [Algebra R S] [Algebra R T] [Algebra S T] - [IsScalarTower R S T] [Algebra.Flat R S] [Algebra.Flat S T] : Algebra.Flat R T where - out := Module.Flat.trans R S T - -@[deprecated (since := "2024-11-08")] alias comp := trans - -/-- If `S` is a flat `R`-algebra and `T` is any `R`-algebra, -then `T ⊗[R] S` is a flat `T`-algebra. -/ -instance baseChange (T : Type w) [CommRing T] [Algebra R S] [Algebra R T] [Algebra.Flat R S] : - Algebra.Flat T (T ⊗[R] S) where - out := Module.Flat.baseChange R T S - -/-- A base change of a flat algebra is flat. -/ -theorem isBaseChange [Algebra R S] (R' : Type w) (S' : Type t) [CommRing R'] [CommRing S'] - [Algebra R R'] [Algebra S S'] [Algebra R' S'] [Algebra R S'] [IsScalarTower R R' S'] - [IsScalarTower R S S'] [h : IsPushout R S R' S'] [Algebra.Flat R R'] : Algebra.Flat S S' where - out := Module.Flat.isBaseChange R S R' S' h.out - -end Algebra.Flat - -/-- A ring homomorphism `f : R →+* S` is flat if `S` is flat as an `R` algebra. -/ -@[algebraize RingHom.Flat.out] -class RingHom.Flat {R : Type u} {S : Type v} [CommRing R] [CommRing S] (f : R →+* S) : Prop where - out : f.toAlgebra.Flat := by infer_instance - -namespace RingHom.Flat - -attribute [instance] out - -/-- The identity of a ring is flat. -/ -instance identity (R : Type u) [CommRing R] : RingHom.Flat (1 : R →+* R) where - -variable {R : Type u} {S : Type v} {T : Type w} [CommRing R] [CommRing S] [CommRing T] - (f : R →+* S) (g : S →+* T) - -/-- Composition of flat ring homomorphisms is flat. -/ -instance comp [RingHom.Flat f] [RingHom.Flat g] : RingHom.Flat (g.comp f) where - out := by - algebraize_only [f, g, g.comp f] - exact Algebra.Flat.trans R S T - -end RingHom.Flat diff --git a/Mathlib/RingTheory/Flat/Basic.lean b/Mathlib/RingTheory/Flat/Basic.lean index 9509f2f734fbb..18985920c6140 100644 --- a/Mathlib/RingTheory/Flat/Basic.lean +++ b/Mathlib/RingTheory/Flat/Basic.lean @@ -56,11 +56,13 @@ See . universe v' u v w +open TensorProduct + namespace Module open Function (Surjective) -open LinearMap Submodule TensorProduct DirectSum +open LinearMap Submodule DirectSum variable (R : Type u) (M : Type v) [CommRing R] [AddCommGroup M] [Module R M] @@ -423,3 +425,70 @@ theorem tensorProduct_mapIncl_injective_of_left end Flat end Module + +section Injective + +variable {R S A B : Type*} [CommRing R] [Ring A] [Algebra R A] [Ring B] [Algebra R B] + [CommSemiring S] [Algebra S A] [SMulCommClass R S A] + +namespace Algebra.TensorProduct + +theorem includeLeft_injective [Module.Flat R A] (hb : Function.Injective (algebraMap R B)) : + Function.Injective (includeLeft : A →ₐ[S] A ⊗[R] B) := by + convert Module.Flat.lTensor_preserves_injective_linearMap (M := A) (Algebra.linearMap R B) hb + |>.comp (_root_.TensorProduct.rid R A).symm.injective + ext; simp + +theorem includeRight_injective [Module.Flat R B] (ha : Function.Injective (algebraMap R A)) : + Function.Injective (includeRight : B →ₐ[R] A ⊗[R] B) := by + convert Module.Flat.rTensor_preserves_injective_linearMap (M := B) (Algebra.linearMap R A) ha + |>.comp (_root_.TensorProduct.lid R B).symm.injective + ext; simp + +end Algebra.TensorProduct + +end Injective + +section Nontrivial + +variable (R : Type*) [CommRing R] + +namespace TensorProduct + +variable (M N : Type*) [AddCommGroup M] [AddCommGroup N] [Module R M] [Module R N] + +/-- If `M`, `N` are `R`-modules, there exists an injective `R`-linear map from `R` to `N`, +and `M` is a nontrivial flat `R`-module, then `M ⊗[R] N` is nontrivial. -/ +theorem nontrivial_of_linearMap_injective_of_flat_left (f : R →ₗ[R] N) (h : Function.Injective f) + [Module.Flat R M] [Nontrivial M] : Nontrivial (M ⊗[R] N) := + Module.Flat.lTensor_preserves_injective_linearMap (M := M) f h |>.comp + (TensorProduct.rid R M).symm.injective |>.nontrivial + +/-- If `M`, `N` are `R`-modules, there exists an injective `R`-linear map from `R` to `M`, +and `N` is a nontrivial flat `R`-module, then `M ⊗[R] N` is nontrivial. -/ +theorem nontrivial_of_linearMap_injective_of_flat_right (f : R →ₗ[R] M) (h : Function.Injective f) + [Module.Flat R N] [Nontrivial N] : Nontrivial (M ⊗[R] N) := + Module.Flat.rTensor_preserves_injective_linearMap (M := N) f h |>.comp + (TensorProduct.lid R N).symm.injective |>.nontrivial + +end TensorProduct + +namespace Algebra.TensorProduct + +variable (A B : Type*) [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] + +/-- If `A`, `B` are `R`-algebras, `R` injects into `B`, +and `A` is a nontrivial flat `R`-algebra, then `A ⊗[R] B` is nontrivial. -/ +theorem nontrivial_of_algebraMap_injective_of_flat_left (h : Function.Injective (algebraMap R B)) + [Module.Flat R A] [Nontrivial A] : Nontrivial (A ⊗[R] B) := + TensorProduct.nontrivial_of_linearMap_injective_of_flat_left R A B (Algebra.linearMap R B) h + +/-- If `A`, `B` are `R`-algebras, `R` injects into `A`, +and `B` is a nontrivial flat `R`-algebra, then `A ⊗[R] B` is nontrivial. -/ +theorem nontrivial_of_algebraMap_injective_of_flat_right (h : Function.Injective (algebraMap R A)) + [Module.Flat R B] [Nontrivial B] : Nontrivial (A ⊗[R] B) := + TensorProduct.nontrivial_of_linearMap_injective_of_flat_right R A B (Algebra.linearMap R A) h + +end Algebra.TensorProduct + +end Nontrivial diff --git a/Mathlib/RingTheory/Flat/CategoryTheory.lean b/Mathlib/RingTheory/Flat/CategoryTheory.lean index ea6d1442dad38..e8aaed01f1d4d 100644 --- a/Mathlib/RingTheory/Flat/CategoryTheory.lean +++ b/Mathlib/RingTheory/Flat/CategoryTheory.lean @@ -52,8 +52,8 @@ lemma iff_lTensor_preserves_shortComplex_exact : ⟨fun _ _ ↦ lTensor_shortComplex_exact _ _, fun H ↦ iff_lTensor_exact.2 <| fun _ _ _ _ _ _ _ _ _ f g h ↦ moduleCat_exact_iff_function_exact _ |>.1 <| - H (.mk (ModuleCat.asHom f) (ModuleCat.asHom g) - (DFunLike.ext _ _ h.apply_apply_eq_zero)) + H (.mk (ModuleCat.ofHom f) (ModuleCat.ofHom g) + (ModuleCat.hom_ext (DFunLike.ext _ _ h.apply_apply_eq_zero))) (moduleCat_exact_iff_function_exact _ |>.2 h)⟩ lemma iff_rTensor_preserves_shortComplex_exact : @@ -62,8 +62,8 @@ lemma iff_rTensor_preserves_shortComplex_exact : ⟨fun _ _ ↦ rTensor_shortComplex_exact _ _, fun H ↦ iff_rTensor_exact.2 <| fun _ _ _ _ _ _ _ _ _ f g h ↦ moduleCat_exact_iff_function_exact _ |>.1 <| - H (.mk (ModuleCat.asHom f) (ModuleCat.asHom g) - (DFunLike.ext _ _ h.apply_apply_eq_zero)) + H (.mk (ModuleCat.ofHom f) (ModuleCat.ofHom g) + (ModuleCat.hom_ext (DFunLike.ext _ _ h.apply_apply_eq_zero))) (moduleCat_exact_iff_function_exact _ |>.2 h)⟩ end Module.Flat diff --git a/Mathlib/RingTheory/Flat/Localization.lean b/Mathlib/RingTheory/Flat/Localization.lean index 9269fb9b8bd69..2de407505a926 100644 --- a/Mathlib/RingTheory/Flat/Localization.lean +++ b/Mathlib/RingTheory/Flat/Localization.lean @@ -3,21 +3,30 @@ Copyright (c) 2024 Junyan Xu. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Junyan Xu -/ -import Mathlib.Algebra.Module.LocalizedModule.Submodule -import Mathlib.RingTheory.Flat.Basic -import Mathlib.RingTheory.Localization.BaseChange +import Mathlib.RingTheory.Flat.Stability +import Mathlib.RingTheory.LocalProperties.Exactness /-! # Flatness and localization -In this file we show that localizations are flat, and flatness is a local property (TODO). +In this file we show that localizations are flat, and flatness is a local property. ## Main result -- `IsLocalization.flat`: a localization of a commutative ring is flat over it. +* `IsLocalization.flat`: a localization of a commutative ring is flat over it. +* `Module.flat_iff_of_isLocalization` : Let `Rₚ` a localization of a commutative ring `R` + and `M` be a module over `Rₚ`. Then `M` is flat over `R` if and only if `M` is flat over `Rₚ`. +* `Module.flat_of_isLocalized_maximal` : Let `M` be a module over a commutative ring `R`. + If the localization of `M` at each maximal ideal `P` is flat over `Rₚ`, then `M` is flat over `R`. +* `Module.flat_of_isLocalized_span` : Let `M` be a module over a commutative ring `R` + and `S` be a set that spans `R`. If the localization of `M` at each `s : S` is flat + over `Localization.Away s`, then `M` is flat over `R`. -/ +open IsLocalizedModule LocalizedModule LinearMap TensorProduct + variable {R : Type*} (S : Type*) [CommRing R] [CommRing S] [Algebra R S] variable (p : Submonoid R) [IsLocalization p S] +variable (M : Type*) [AddCommGroup M] [Module R M] [Module S M] [IsScalarTower R S M] include p in theorem IsLocalization.flat : Module.Flat R S := @@ -30,3 +39,66 @@ theorem IsLocalization.flat : Module.Flat R S := simpa [this, - Subtype.val_injective] using Subtype.val_injective instance Localization.flat : Module.Flat R (Localization p) := IsLocalization.flat _ p + +namespace Module + +include p in +theorem flat_iff_of_isLocalization : Flat S M ↔ Flat R M := + have := isLocalizedModule_id p M S + have := IsLocalization.flat S p + ⟨fun _ ↦ .trans R S M, fun _ ↦ .of_isLocalizedModule S p .id⟩ + +private lemma aux (I : Ideal R) (s : Submonoid R) : + have hM := isBaseChange s (Localization s) (mkLinearMap s M) + have hIM := isBaseChange s (Localization s) (mkLinearMap s (I ⊗[R] M)) + let e := (hIM.equiv.restrictScalars R).symm ≪≫ₗ + leftComm _ _ _ _ ≪≫ₗ (hM.equiv.restrictScalars R).lTensor I + LocalizedModule.map s (TensorProduct.lift <| lsmul R M ∘ₗ I.subtype) = + TensorProduct.lift (lsmul R (LocalizedModule s M) ∘ₗ I.subtype) ∘ₗ e.toLinearMap := by + refine linearMap_ext s (mkLinearMap s _) (mkLinearMap s _) ?_ + ext m i + rw [AlgebraTensorModule.curry_apply, curry_apply, restrictScalars_apply, LinearMap.comp_apply, + restrictScalars_apply, mkLinearMap_apply, AlgebraTensorModule.curry_apply, curry_apply, + restrictScalars_apply] + simpa [-mkLinearMap_apply, IsBaseChange.equiv_symm_apply, IsBaseChange.equiv_tmul] using + (mkLinearMap_apply _ _ _).symm.trans (map_smul (mkLinearMap s M) _ _) + +variable (Mₚ : ∀ (P : Ideal R) [P.IsMaximal], Type*) + [∀ (P : Ideal R) [P.IsMaximal], AddCommGroup (Mₚ P)] + [∀ (P : Ideal R) [P.IsMaximal], Module R (Mₚ P)] + (f : ∀ (P : Ideal R) [P.IsMaximal], M →ₗ[R] Mₚ P) + [∀ (P : Ideal R) [P.IsMaximal], IsLocalizedModule P.primeCompl (f P)] + +theorem flat_of_localized_maximal + (h : ∀ (J : Ideal R) [J.IsMaximal], Flat R (LocalizedModule J.primeCompl M)) : + Flat R M := + (flat_iff _ _).mpr fun I fg ↦ injective_of_localized_maximal _ fun J hJ ↦ by + rw [← LinearMap.coe_restrictScalars R, aux] + simpa using (flat_iff _ _).mp (h J) fg + +include f in +theorem flat_of_isLocalized_maixmal (H : ∀ (P : Ideal R) [P.IsMaximal], Flat R (Mₚ P)) : + Module.Flat R M := + flat_of_localized_maximal M fun P _ ↦ .of_linearEquiv _ _ _ (iso _ (f P)) + +variable (s : Set R) (spn : Ideal.span s = ⊤) + (Mₛ : ∀ _ : s, Type*) + [∀ r : s, AddCommGroup (Mₛ r)] + [∀ r : s, Module R (Mₛ r)] + (g : ∀ r : s, M →ₗ[R] Mₛ r) + [∀ r : s, IsLocalizedModule (.powers r.1) (g r)] +include spn + +theorem flat_of_localized_span + (h : ∀ r : s, Flat R (LocalizedModule (.powers r.1) M)) : + Flat R M := + (Module.flat_iff _ _).mpr fun I fg ↦ injective_of_localized_span s spn _ fun r ↦ by + rw [← LinearMap.coe_restrictScalars R, aux] + simpa using (Module.flat_iff _ _).mp (h r) fg + +include g in +theorem flat_of_isLocalized_span (H : ∀ r : s, Module.Flat R (Mₛ r)) : + Module.Flat R M := + flat_of_localized_span M s spn fun r ↦ .of_linearEquiv _ _ _ (iso _ (g r)) + +end Module diff --git a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean index 82a5c54c0a72c..1b14cfce13ed0 100644 --- a/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean +++ b/Mathlib/RingTheory/GradedAlgebra/HomogeneousLocalization.lean @@ -363,7 +363,7 @@ instance hasPow : Pow (HomogeneousLocalization 𝒜 x) ℕ where instance : Add (HomogeneousLocalization 𝒜 x) where add := - Quotient.map₂' (· + ·) + Quotient.map₂ (· + ·) fun c1 c2 (h : Localization.mk _ _ = Localization.mk _ _) c3 c4 (h' : Localization.mk _ _ = Localization.mk _ _) => by change Localization.mk _ _ = Localization.mk _ _ @@ -376,7 +376,7 @@ instance : Sub (HomogeneousLocalization 𝒜 x) where sub z1 z2 := z1 + -z2 instance : Mul (HomogeneousLocalization 𝒜 x) where mul := - Quotient.map₂' (· * ·) + Quotient.map₂ (· * ·) fun c1 c2 (h : Localization.mk _ _ = Localization.mk _ _) c3 c4 (h' : Localization.mk _ _ = Localization.mk _ _) => by change Localization.mk _ _ = Localization.mk _ _ diff --git a/Mathlib/RingTheory/HahnSeries/Multiplication.lean b/Mathlib/RingTheory/HahnSeries/Multiplication.lean index 7719c9ebf8a30..8660ddb736c28 100644 --- a/Mathlib/RingTheory/HahnSeries/Multiplication.lean +++ b/Mathlib/RingTheory/HahnSeries/Multiplication.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson, Scott Carnahan -/ import Mathlib.Algebra.Algebra.Subalgebra.Basic +import Mathlib.Algebra.Module.BigOperators import Mathlib.Data.Finset.MulAntidiagonal import Mathlib.Data.Finset.SMulAntidiagonal import Mathlib.GroupTheory.GroupAction.Ring diff --git a/Mathlib/RingTheory/HahnSeries/Summable.lean b/Mathlib/RingTheory/HahnSeries/Summable.lean index c9ea82db6087b..41f0ce1b8f513 100644 --- a/Mathlib/RingTheory/HahnSeries/Summable.lean +++ b/Mathlib/RingTheory/HahnSeries/Summable.lean @@ -267,7 +267,22 @@ end AddCommGroup section SMul -variable [PartialOrder Γ] [PartialOrder Γ'] [AddCommMonoid R] [AddCommMonoid V] [SMulWithZero R V] +variable [PartialOrder Γ] [PartialOrder Γ'] [AddCommMonoid V] + +instance [Zero R] [SMulWithZero R V] : SMul R (SummableFamily Γ' V β) := + ⟨fun r t => + { toFun := r • t + isPWO_iUnion_support' := t.isPWO_iUnion_support.mono (Set.iUnion_mono fun i => + Pi.smul_apply r t i ▸ Function.support_const_smul_subset r _) + finite_co_support' := by + intro g + refine (t.finite_co_support g).subset ?_ + intro i hi + simp only [Pi.smul_apply, smul_coeff, ne_eq, Set.mem_setOf_eq] at hi + simp only [Function.mem_support, ne_eq] + exact right_ne_zero_of_smul hi } ⟩ + +variable [AddCommMonoid R] [SMulWithZero R V] theorem smul_support_subset_prod (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) (gh : Γ × Γ') : @@ -322,13 +337,15 @@ theorem finite_co_support_prod_smul (s : SummableFamily Γ R α) /-- An elementwise scalar multiplication of one summable family on another. -/ @[simps] -def FamilySMul (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) : +def smul (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) : (SummableFamily Γ' V (α × β)) where toFun ab := (of R).symm (s (ab.1) • ((of R) (t (ab.2)))) isPWO_iUnion_support' := isPWO_iUnion_support_prod_smul s.isPWO_iUnion_support t.isPWO_iUnion_support finite_co_support' g := finite_co_support_prod_smul s t g +@[deprecated (since := "2024-11-17")] noncomputable alias FamilySMul := smul + theorem sum_vAddAntidiagonal_eq (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) (g : Γ') (a : α × β) : ∑ x ∈ VAddAntidiagonal (s a.1).isPWO_support' (t a.2).isPWO_support' g, (s a.1).coeff x.1 • @@ -341,12 +358,12 @@ theorem sum_vAddAntidiagonal_eq (s : SummableFamily Γ R α) (t : SummableFamily · exact smul_eq_zero_of_left hs ((t a.2).coeff gh.2) · simp_all -theorem family_smul_coeff {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] +theorem smul_coeff {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) (g : Γ') : - (FamilySMul s t).hsum.coeff g = ∑ gh ∈ VAddAntidiagonal s.isPWO_iUnion_support + (smul s t).hsum.coeff g = ∑ gh ∈ VAddAntidiagonal s.isPWO_iUnion_support t.isPWO_iUnion_support g, (s.hsum.coeff gh.1) • (t.hsum.coeff gh.2) := by rw [hsum_coeff] - simp only [hsum_coeff_eq_sum, FamilySMul_toFun, HahnModule.smul_coeff, Equiv.symm_apply_apply] + simp only [hsum_coeff_eq_sum, smul_toFun, HahnModule.smul_coeff, Equiv.symm_apply_apply] simp_rw [sum_vAddAntidiagonal_eq, Finset.smul_sum, Finset.sum_smul] rw [← sum_finsum_comm _ _ <| fun gh _ => smul_support_finite s t gh] refine sum_congr rfl fun gh _ => ?_ @@ -358,11 +375,13 @@ theorem family_smul_coeff {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] Set.mem_setOf_eq, Prod.forall, coeff_support, mem_product] exact hsupp ab.1 ab.2 hab -theorem hsum_family_smul {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] +@[deprecated (since := "2024-11-17")] alias family_smul_coeff := smul_coeff + +theorem smul_hsum {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] (s : SummableFamily Γ R α) (t : SummableFamily Γ' V β) : - (FamilySMul s t).hsum = (of R).symm (s.hsum • (of R) (t.hsum)) := by + (smul s t).hsum = (of R).symm (s.hsum • (of R) (t.hsum)) := by ext g - rw [family_smul_coeff s t g, HahnModule.smul_coeff, Equiv.symm_apply_apply] + rw [smul_coeff s t g, HahnModule.smul_coeff, Equiv.symm_apply_apply] refine Eq.symm (sum_of_injOn (fun a ↦ a) (fun _ _ _ _ h ↦ h) (fun _ hgh => ?_) (fun gh _ hgh => ?_) fun _ _ => by simp) · simp_all only [mem_coe, mem_vaddAntidiagonal, mem_support, ne_eq, Set.mem_iUnion, and_true] @@ -377,11 +396,13 @@ theorem hsum_family_smul {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] · exact smul_eq_zero_of_left h (t.hsum.coeff gh.2) · simp_all +@[deprecated (since := "2024-11-17")] alias hsum_family_smul := smul_hsum + instance [AddCommMonoid R] [SMulWithZero R V] : SMul (HahnSeries Γ R) (SummableFamily Γ' V β) where - smul x t := Equiv (Equiv.punitProd β) <| FamilySMul (single x) t + smul x t := Equiv (Equiv.punitProd β) <| smul (single x) t theorem smul_eq {x : HahnSeries Γ R} {t : SummableFamily Γ' V β} : - x • t = Equiv (Equiv.punitProd β) (FamilySMul (single x) t) := + x • t = Equiv (Equiv.punitProd β) (smul (single x) t) := rfl @[simp] @@ -393,7 +414,7 @@ theorem smul_apply {x : HahnSeries Γ R} {s : SummableFamily Γ' V α} {a : α} theorem hsum_smul_module {R} {V} [Semiring R] [AddCommMonoid V] [Module R V] {x : HahnSeries Γ R} {s : SummableFamily Γ' V α} : (x • s).hsum = (of R).symm (x • of R s.hsum) := by - rw [smul_eq, hsum_equiv, hsum_family_smul, hsum_single] + rw [smul_eq, hsum_equiv, smul_hsum, hsum_single] end SMul @@ -427,6 +448,40 @@ theorem hsum_sub {R : Type*} [Ring R] {s t : SummableFamily Γ R α} : (s - t).hsum = s.hsum - t.hsum := by rw [← lsum_apply, LinearMap.map_sub, lsum_apply, lsum_apply] +theorem isPWO_iUnion_support_prod_mul {s : α → HahnSeries Γ R} {t : β → HahnSeries Γ R} + (hs : (⋃ a, (s a).support).IsPWO) (ht : (⋃ b, (t b).support).IsPWO) : + (⋃ (a : α × β), ((fun a ↦ ((s a.1) * (t a.2))) a).support).IsPWO := + isPWO_iUnion_support_prod_smul hs ht + +theorem finite_co_support_prod_mul (s : SummableFamily Γ R α) + (t : SummableFamily Γ R β) (g : Γ) : + Finite {(a : α × β) | ((fun (a : α × β) ↦ (s a.1 * t a.2)) a).coeff g ≠ 0} := + finite_co_support_prod_smul s t g + +/-- A summable family given by pointwise multiplication of a pair of summable families. -/ +@[simps] +def mul (s : SummableFamily Γ R α) (t : SummableFamily Γ R β) : + (SummableFamily Γ R (α × β)) where + toFun a := s (a.1) * t (a.2) + isPWO_iUnion_support' := + isPWO_iUnion_support_prod_mul s.isPWO_iUnion_support t.isPWO_iUnion_support + finite_co_support' g := finite_co_support_prod_mul s t g + +theorem mul_eq_smul {β : Type*} (s : SummableFamily Γ R α) (t : SummableFamily Γ R β) : + mul s t = smul s t := + rfl + +theorem mul_coeff {β : Type*} (s : SummableFamily Γ R α) (t : SummableFamily Γ R β) (g : Γ) : + (mul s t).hsum.coeff g = ∑ gh ∈ addAntidiagonal s.isPWO_iUnion_support + t.isPWO_iUnion_support g, (s.hsum.coeff gh.1) * (t.hsum.coeff gh.2) := by + simp_rw [← smul_eq_mul, mul_eq_smul] + exact smul_coeff s t g + +theorem hsum_mul {β : Type*} (s : SummableFamily Γ R α) (t : SummableFamily Γ R β) : + (mul s t).hsum = s.hsum * t.hsum := by + rw [← smul_eq_mul, mul_eq_smul] + exact smul_hsum s t + end Semiring section OfFinsupp diff --git a/Mathlib/RingTheory/Ideal/Cotangent.lean b/Mathlib/RingTheory/Ideal/Cotangent.lean index 04fd59250aa5c..9f2e89438bbbc 100644 --- a/Mathlib/RingTheory/Ideal/Cotangent.lean +++ b/Mathlib/RingTheory/Ideal/Cotangent.lean @@ -196,6 +196,7 @@ def mapCotangent (I₁ : Ideal A) (I₂ : Ideal B) (f : A →ₐ[R] B) (h : I₁ ((I₂ • ⊤ : Submodule B I₂).restrictScalars R) ?_ ?_ · exact f.toLinearMap.restrict (p := I₁.restrictScalars R) (q := I₂.restrictScalars R) h · intro x hx + rw [Submodule.restrictScalars_mem] at hx refine Submodule.smul_induction_on hx ?_ (fun _ _ ↦ add_mem) rintro a ha ⟨b, hb⟩ - simp only [SetLike.mk_smul_mk, smul_eq_mul, Submodule.mem_comap, Submodule.restrictScalars_mem] diff --git a/Mathlib/RingTheory/Ideal/Maps.lean b/Mathlib/RingTheory/Ideal/Maps.lean index e2a631a34c0a9..8c11e7e809c5d 100644 --- a/Mathlib/RingTheory/Ideal/Maps.lean +++ b/Mathlib/RingTheory/Ideal/Maps.lean @@ -321,6 +321,19 @@ theorem map_eq_submodule_map (f : R →+* S) [h : RingHomSurjective f] (I : Idea I.map f = Submodule.map f.toSemilinearMap I := Submodule.ext fun _ => mem_map_iff_of_surjective f h.1 +open Function in +theorem IsMaximal.comap_piEvalRingHom {ι : Type*} {R : ι → Type*} [∀ i, Semiring (R i)] + {i : ι} {I : Ideal (R i)} (h : I.IsMaximal) : (I.comap <| Pi.evalRingHom R i).IsMaximal := by + refine isMaximal_iff.mpr ⟨I.ne_top_iff_one.mp h.ne_top, fun J x le hxI hxJ ↦ ?_⟩ + have ⟨r, y, hy, eq⟩ := h.exists_inv hxI + classical + convert J.add_mem (J.mul_mem_left (update 0 i r) hxJ) + (b := update 1 i y) (le <| by apply update_same i y 1 ▸ hy) + ext j + obtain rfl | ne := eq_or_ne j i + · simpa [eq_comm] using eq + · simp [update_noteq ne] + end Surjective section Injective @@ -353,7 +366,7 @@ theorem comap_of_equiv {I : Ideal R} (f : R ≃+* S) : /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `map f I = comap f.symm I`. -/ theorem map_comap_of_equiv {I : Ideal R} (f : R ≃+* S) : I.map (f : R →+* S) = I.comap f.symm := le_antisymm (Ideal.map_le_comap_of_inverse _ _ _ (Equiv.left_inv' _)) - (Ideal.comap_le_map_of_inverse _ _ _ (Equiv.right_inv' _)) + (Ideal.comap_le_map_of_inverse _ _ _ (Equiv.right_inv' _)) /-- If `f : R ≃+* S` is a ring isomorphism and `I : Ideal R`, then `comap f.symm I = map f I`. -/ @[simp] @@ -385,6 +398,56 @@ theorem mem_map_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e · rintro ⟨x, hx, rfl⟩ exact mem_map_of_mem e hx +section Bijective + +variable (hf : Function.Bijective f) {I : Ideal R} {K : Ideal S} +include hf + +/-- Special case of the correspondence theorem for isomorphic rings -/ +def relIsoOfBijective : Ideal S ≃o Ideal R where + toFun := comap f + invFun := map f + left_inv := map_comap_of_surjective _ hf.2 + right_inv J := + le_antisymm + (fun _ h ↦ have ⟨y, hy, eq⟩ := (mem_map_iff_of_surjective _ hf.2).mp h; hf.1 eq ▸ hy) + le_comap_map + map_rel_iff' {_ _} := by + refine ⟨fun h ↦ ?_, comap_mono⟩ + have := map_mono (f := f) h + simpa only [Equiv.coe_fn_mk, map_comap_of_surjective f hf.2] using this + +theorem comap_le_iff_le_map : comap f K ≤ I ↔ K ≤ map f I := + ⟨fun h => le_map_of_comap_le_of_surjective f hf.right h, fun h => + (relIsoOfBijective f hf).right_inv I ▸ comap_mono h⟩ + +lemma comap_map_of_bijective : (I.map f).comap f = I := + le_antisymm ((comap_le_iff_le_map f hf).mpr fun _ ↦ id) le_comap_map + +theorem isMaximal_map_iff_of_bijective : IsMaximal (map f I) ↔ IsMaximal I := by + simpa only [isMaximal_def] using (relIsoOfBijective _ hf).symm.isCoatom_iff _ + +theorem isMaximal_comap_iff_of_bijective : IsMaximal (comap f K) ↔ IsMaximal K := by + simpa only [isMaximal_def] using (relIsoOfBijective _ hf).isCoatom_iff _ + +alias ⟨_, IsMaximal.map_bijective⟩ := isMaximal_map_iff_of_bijective +alias ⟨_, IsMaximal.comap_bijective⟩ := isMaximal_comap_iff_of_bijective + +/-- A ring isomorphism sends a maximal ideal to a maximal ideal. -/ +instance map_isMaximal_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e : E) + {p : Ideal R} [hp : p.IsMaximal] : (map e p).IsMaximal := + hp.map_bijective e (EquivLike.bijective e) + +theorem isMaximal_iff_of_bijective : (⊥ : Ideal R).IsMaximal ↔ (⊥ : Ideal S).IsMaximal := + ⟨fun h ↦ map_bot (f := f) ▸ h.map_bijective f hf, fun h ↦ have e := RingEquiv.ofBijective f hf + map_bot (f := e.symm) ▸ h.map_bijective _ e.symm.bijective⟩ + +@[deprecated (since := "2024-12-07")] alias map.isMaximal := IsMaximal.map_bijective +@[deprecated (since := "2024-12-07")] alias comap.isMaximal := IsMaximal.comap_bijective +@[deprecated (since := "2024-12-07")] alias RingEquiv.bot_maximal_iff := isMaximal_iff_of_bijective + +end Bijective + end Semiring section Ring @@ -431,7 +494,7 @@ theorem map_eq_top_or_isMaximal_of_surjective (hf : Function.Surjective f) {I : · exact map_le_iff_le_comap.1 (le_of_lt hJ) · exact fun h => hJ.right (le_map_of_comap_le_of_surjective f hf (le_of_eq h.symm)) -theorem comap_isMaximal_of_surjective (hf : Function.Surjective f) {K : Ideal S} [H : IsMaximal K]: +theorem comap_isMaximal_of_surjective (hf : Function.Surjective f) {K : Ideal S} [H : IsMaximal K] : IsMaximal (comap f K) := by refine ⟨⟨comap_ne_top _ H.1.1, fun J hJ => ?_⟩⟩ suffices map f J = ⊤ by @@ -459,48 +522,6 @@ theorem comap_le_comap_iff_of_surjective (hf : Function.Surjective f) (I J : Ide end Surjective -section Bijective - -/-- Special case of the correspondence theorem for isomorphic rings -/ -def relIsoOfBijective (hf : Function.Bijective f) : Ideal S ≃o Ideal R where - toFun := comap f - invFun := map f - left_inv := (relIsoOfSurjective f hf.right).left_inv - right_inv J := - Subtype.ext_iff.1 - ((relIsoOfSurjective f hf.right).right_inv ⟨J, comap_bot_le_of_injective f hf.left⟩) - map_rel_iff' {_ _} := (relIsoOfSurjective f hf.right).map_rel_iff' - -theorem comap_le_iff_le_map (hf : Function.Bijective f) {I : Ideal R} {K : Ideal S} : - comap f K ≤ I ↔ K ≤ map f I := - ⟨fun h => le_map_of_comap_le_of_surjective f hf.right h, fun h => - (relIsoOfBijective f hf).right_inv I ▸ comap_mono h⟩ - -lemma comap_map_of_bijective (hf : Function.Bijective f) {I : Ideal R} : - (I.map f).comap f = I := - le_antisymm ((comap_le_iff_le_map f hf).mpr fun _ ↦ id) le_comap_map - -theorem map.isMaximal (hf : Function.Bijective f) {I : Ideal R} (H : IsMaximal I) : - IsMaximal (map f I) := by - refine - or_iff_not_imp_left.1 (map_eq_top_or_isMaximal_of_surjective f hf.right H) fun h => H.1.1 ?_ - calc - I = comap f (map f I) := ((relIsoOfBijective f hf).right_inv I).symm - _ = comap f ⊤ := by rw [h] - _ = ⊤ := by rw [comap_top] - -/-- A ring isomorphism sends a maximal ideal to a maximal ideal. -/ -instance map_isMaximal_of_equiv {E : Type*} [EquivLike E R S] [RingEquivClass E R S] (e : E) - {p : Ideal R} [hp : p.IsMaximal] : (map e p).IsMaximal := - map.isMaximal e (EquivLike.bijective e) hp - -end Bijective - -theorem RingEquiv.bot_maximal_iff (e : R ≃+* S) : - (⊥ : Ideal R).IsMaximal ↔ (⊥ : Ideal S).IsMaximal := - ⟨fun h => map_bot (f := e.toRingHom) ▸ map.isMaximal e.toRingHom e.bijective h, fun h => - map_bot (f := e.symm.toRingHom) ▸ map.isMaximal e.symm.toRingHom e.symm.bijective h⟩ - end Ring section CommRing diff --git a/Mathlib/RingTheory/Ideal/Operations.lean b/Mathlib/RingTheory/Ideal/Operations.lean index 7218ec0a9688e..a04061874ab5e 100644 --- a/Mathlib/RingTheory/Ideal/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Operations.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau -/ import Mathlib.Algebra.Algebra.Operations +import Mathlib.Algebra.Module.BigOperators import Mathlib.Data.Fintype.Lattice import Mathlib.RingTheory.Coprime.Lemmas import Mathlib.RingTheory.Ideal.Basic @@ -22,122 +23,61 @@ open Pointwise namespace Submodule +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 + | mem _ h => exact mem_set_smul_of_mem_mem h hn + | zero => rw [zero_smul]; exact Submodule.zero_mem _ + | add _ _ _ _ ihr ihs => rw [add_smul]; exact Submodule.add_mem _ ihr ihs + | smul _ _ hr => + 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 + +lemma span_singleton_toAddSubgroup_eq_zmultiples (a : ℤ) : + (span ℤ {a}).toAddSubgroup = AddSubgroup.zmultiples a := by + ext i + simp [Ideal.mem_span_singleton', AddSubgroup.mem_zmultiples_iff] + +@[simp] lemma _root_.Ideal.span_singleton_toAddSubgroup_eq_zmultiples (a : ℤ) : + (Ideal.span {a}).toAddSubgroup = AddSubgroup.zmultiples a := + Submodule.span_singleton_toAddSubgroup_eq_zmultiples _ + variable {R : Type u} {M : Type v} {M' F G : Type*} section Semiring variable [Semiring R] [AddCommMonoid M] [Module R M] -instance : SMul (Ideal R) (Submodule R M) where - smul I N := - { __ := I.toAddSubmonoid • N.toAddSubmonoid - smul_mem' := fun r m hm ↦ AddSubmonoid.smul_induction_on hm - (fun m hm n ↦ by rw [smul_smul]; exact AddSubmonoid.smul_mem_smul <| I.smul_mem _ hm) - fun m₁ m₂ h₁ h₂ ↦ by rw [smul_add]; exact (I.1 • N.1).add_mem h₁ h₂ } - /-- This duplicates the global `smul_eq_mul`, but doesn't have to unfold anywhere near as much to apply. -/ protected theorem _root_.Ideal.smul_eq_mul (I J : Ideal R) : I • J = I * J := rfl -variable {I J : Ideal R} {N P : Submodule R M} - -theorem smul_toAddSubmonoid : (I • N).toAddSubmonoid = I.toAddSubmonoid • N.toAddSubmonoid := rfl - -theorem smul_mem_smul {r} {n} (hr : r ∈ I) (hn : n ∈ N) : r • n ∈ I • N := - AddSubmonoid.smul_mem_smul hr hn - -theorem smul_le : I • N ≤ P ↔ ∀ r ∈ I, ∀ n ∈ N, r • n ∈ P := - AddSubmonoid.smul_le - -@[simp, norm_cast] -lemma coe_set_smul : (I : Set R) • N = I • N := - 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) (smul : ∀ r ∈ I, ∀ n ∈ N, p (r • n)) - (add : ∀ x y, p x → p y → p (x + y)) : p x := - AddSubmonoid.smul_induction_on H smul add - -/-- Dependent version of `Submodule.smul_induction_on`. -/ -@[elab_as_elim] -theorem smul_induction_on' {x : M} (hx : x ∈ I • N) {p : ∀ x, x ∈ I • N → Prop} - (smul : ∀ (r : R) (hr : r ∈ I) (n : M) (hn : n ∈ N), p (r • n) (smul_mem_smul hr hn)) - (add : ∀ x hx y hy, p x hx → p y hy → p (x + y) (add_mem ‹_› ‹_›)) : p x hx := by - refine Exists.elim ?_ fun (h : x ∈ I • N) (H : p x h) ↦ H - exact smul_induction_on hx (fun a ha x hx ↦ ⟨_, smul _ ha _ hx⟩) - fun x y ⟨_, hx⟩ ⟨_, hy⟩ ↦ ⟨_, add _ _ _ _ hx hy⟩ +variable {I : Ideal R} {N : Submodule R M} theorem smul_le_right : I • N ≤ N := smul_le.2 fun r _ _ ↦ N.smul_mem r -theorem smul_mono (hij : I ≤ J) (hnp : N ≤ P) : I • N ≤ J • P := - AddSubmonoid.smul_le_smul hij hnp - -theorem smul_mono_left (h : I ≤ J) : I • N ≤ J • N := - smul_mono h le_rfl - -instance : CovariantClass (Ideal R) (Submodule R M) HSMul.hSMul LE.le := - ⟨fun _ _ => smul_mono le_rfl⟩ - -@[deprecated smul_mono_right (since := "2024-03-31")] -protected theorem smul_mono_right (h : N ≤ P) : I • N ≤ I • P := - _root_.smul_mono_right I h - theorem map_le_smul_top (I : Ideal R) (f : R →ₗ[R] M) : Submodule.map f I ≤ I • (⊤ : Submodule R M) := by rintro _ ⟨y, hy, rfl⟩ rw [← mul_one y, ← smul_eq_mul, f.map_smul] exact smul_mem_smul hy mem_top -variable (I J N P) - -@[simp] -theorem smul_bot : I • (⊥ : Submodule R M) = ⊥ := - toAddSubmonoid_injective <| AddSubmonoid.addSubmonoid_smul_bot _ - -@[simp] -theorem bot_smul : (⊥ : Ideal R) • N = ⊥ := - le_bot_iff.mp <| smul_le.mpr <| by rintro _ rfl _ _; rw [zero_smul]; exact zero_mem _ +variable (I N) @[simp] theorem top_smul : (⊤ : Ideal R) • N = N := le_antisymm smul_le_right fun r hri => one_smul R r ▸ smul_mem_smul mem_top hri -theorem smul_sup : I • (N ⊔ P) = I • N ⊔ I • P := - toAddSubmonoid_injective <| by - simp only [smul_toAddSubmonoid, sup_toAddSubmonoid, AddSubmonoid.addSubmonoid_smul_sup] - -theorem sup_smul : (I ⊔ J) • N = I • N ⊔ J • N := - le_antisymm (smul_le.mpr fun mn hmn p hp ↦ by - obtain ⟨m, hm, n, hn, rfl⟩ := mem_sup.mp hmn - rw [add_smul]; exact add_mem_sup (smul_mem_smul hm hp) <| smul_mem_smul hn hp) - (sup_le (smul_mono_left le_sup_left) <| smul_mono_left le_sup_right) - -protected theorem smul_assoc : (I • J) • N = I • J • N := - le_antisymm - (smul_le.2 fun _ hrsij t htn ↦ smul_induction_on hrsij - (fun r hr s hs ↦ smul_assoc r s t ▸ smul_mem_smul hr (smul_mem_smul hs htn)) - fun x y ↦ (add_smul x y t).symm ▸ add_mem) - (smul_le.2 fun r hr _ hsn ↦ smul_induction_on hsn - (fun j hj n hn ↦ (smul_assoc r j n).symm ▸ smul_mem_smul (smul_mem_smul hr hj) hn) - fun m₁ m₂ ↦ (smul_add r m₁ m₂) ▸ add_mem) - -@[deprecated smul_inf_le (since := "2024-03-31")] -protected theorem smul_inf_le (M₁ M₂ : Submodule R M) : - I • (M₁ ⊓ M₂) ≤ I • M₁ ⊓ I • M₂ := smul_inf_le _ _ _ - -theorem smul_iSup {ι : Sort*} {I : Ideal R} {t : ι → Submodule R M} : I • iSup t = ⨆ i, I • t i := - toAddSubmonoid_injective <| by - simp only [smul_toAddSubmonoid, iSup_toAddSubmonoid, AddSubmonoid.smul_iSup] - -@[deprecated smul_iInf_le (since := "2024-03-31")] -protected theorem smul_iInf_le {ι : Sort*} {I : Ideal R} {t : ι → Submodule R M} : - I • iInf t ≤ ⨅ i, I • t i := - smul_iInf_le - theorem mem_of_span_top_of_smul_mem (M' : Submodule R M) (s : Set R) (hs : Ideal.span s = ⊤) (x : M) (H : ∀ r : s, (r : R) • x ∈ M') : x ∈ M' := by suffices LinearMap.range (LinearMap.toSpanSingleton R M x) ≤ M' by @@ -217,16 +157,10 @@ theorem ideal_span_singleton_smul (r : R) (N : Submodule R M) : submodule `M'` of `x`, we only need to show that `r ^ n • x ∈ M'` for some `n` for each `r : s`. -/ theorem mem_of_span_eq_top_of_smul_pow_mem (M' : Submodule R M) (s : Set R) (hs : Ideal.span s = ⊤) (x : M) (H : ∀ r : s, ∃ n : ℕ, ((r : R) ^ n : R) • x ∈ M') : x ∈ M' := by - obtain ⟨s', hs₁, hs₂⟩ := (Ideal.span_eq_top_iff_finite _).mp hs - replace H : ∀ r : s', ∃ n : ℕ, ((r : R) ^ n : R) • x ∈ M' := fun r => H ⟨_, hs₁ r.2⟩ - choose n₁ n₂ using H - let N := s'.attach.sup n₁ - have hs' := Ideal.span_pow_eq_top (s' : Set R) hs₂ N - apply M'.mem_of_span_top_of_smul_mem _ hs' + choose f hf using H + apply M'.mem_of_span_top_of_smul_mem _ (Ideal.span_range_pow_eq_top s hs f) rintro ⟨_, r, hr, rfl⟩ - convert M'.smul_mem (r ^ (N - n₁ ⟨r, hr⟩)) (n₂ ⟨r, hr⟩) using 1 - simp only [Subtype.coe_mk, smul_smul, ← pow_add] - rw [tsub_add_cancel_of_le (Finset.le_sup (s'.mem_attach _) : n₁ ⟨r, hr⟩ ≤ N)] + exact hf r open Pointwise in @[simp] @@ -422,11 +356,23 @@ theorem prod_mem_prod {ι : Type*} {s : Finset ι} {I : ι → Ideal R} {x : ι theorem mul_le_right : I * J ≤ I := Ideal.mul_le.2 fun _ hr _ _ => I.mul_mem_right _ hr -@[simp] +#adaptation_note +/-- +On nightly-2024-11-12, we had to add `nolint simpNF` to the following lemma, +as otherwise we get a deterministic timeout in typeclass inference. +This should be investigated. +-/ +@[simp, nolint simpNF] theorem sup_mul_right_self : I ⊔ I * J = I := sup_eq_left.2 Ideal.mul_le_right -@[simp] +#adaptation_note +/-- +On nightly-2024-11-12, we had to add `nolint simpNF` to the following lemma, +as otherwise we get a deterministic timeout in typeclass inference. +This should be investigated. +-/ +@[simp, nolint simpNF] theorem mul_right_self_sup : I * J ⊔ I = I := sup_eq_right.2 Ideal.mul_le_right diff --git a/Mathlib/RingTheory/Ideal/Over.lean b/Mathlib/RingTheory/Ideal/Over.lean index ebb045e9944ca..876ab2aa23179 100644 --- a/Mathlib/RingTheory/Ideal/Over.lean +++ b/Mathlib/RingTheory/Ideal/Over.lean @@ -88,7 +88,7 @@ theorem injective_quotient_le_comap_map (P : Ideal R[X]) : R[x] / P → (R / (P ∩ R))[x] / (P / (P ∩ R)) ``` commutes. It is used, for instance, in the proof of `quotient_mk_comp_C_is_integral_of_jacobson`, -in the file `RingTheory.Jacobson`. +in the file `Mathlib.RingTheory.Jacobson.Polynomial`. -/ theorem quotient_mk_maps_eq (P : Ideal R[X]) : ((Quotient.mk (map (mapRingHom (Quotient.mk (P.comap (C : R →+* R[X])))) P)).comp C).comp @@ -138,24 +138,24 @@ theorem comap_eq_of_scalar_tower_quotient [Algebra R S] [Algebra (R ⧸ p) (S · intro hx rw [hx, RingHom.map_zero] -/-- If `P` lies over `p`, then `R / p` has a canonical map to `S / P`. -/ -def Quotient.algebraQuotientOfLEComap (h : p ≤ comap f P) : Algebra (R ⧸ p) (S ⧸ P) := - RingHom.toAlgebra <| quotientMap _ f h +variable [Algebra R S] /-- `R / p` has a canonical map to `S / pS`. -/ -instance Quotient.algebraQuotientMapQuotient : Algebra (R ⧸ p) (S ⧸ map f p) := +instance Quotient.algebraQuotientMapQuotient : Algebra (R ⧸ p) (S ⧸ map (algebraMap R S) p) := Ideal.Quotient.algebraQuotientOfLEComap le_comap_map @[simp] theorem Quotient.algebraMap_quotient_map_quotient (x : R) : + letI f := algebraMap R S algebraMap (R ⧸ p) (S ⧸ map f p) (Ideal.Quotient.mk p x) = Ideal.Quotient.mk (map f p) (f x) := rfl @[simp] theorem Quotient.mk_smul_mk_quotient_map_quotient (x : R) (y : S) : + letI f := algebraMap R S Quotient.mk p x • Quotient.mk (map f p) y = Quotient.mk (map f p) (f x * y) := - rfl + Algebra.smul_def _ _ instance Quotient.tower_quotient_map_quotient [Algebra R S] : IsScalarTower R (R ⧸ p) (S ⧸ map (algebraMap R S) p) := @@ -164,7 +164,7 @@ instance Quotient.tower_quotient_map_quotient [Algebra R S] : Quotient.mk_algebraMap] instance QuotientMapQuotient.isNoetherian [Algebra R S] [IsNoetherian R S] (I : Ideal R) : - IsNoetherian (R ⧸ I) (S ⧸ Ideal.map (algebraMap R S) I) := + IsNoetherian (R ⧸ I) (S ⧸ I.map (algebraMap R S)) := isNoetherian_of_tower R <| isNoetherian_of_surjective S (Ideal.Quotient.mkₐ R _).toLinearMap <| LinearMap.range_eq_top.mpr Ideal.Quotient.mk_surjective diff --git a/Mathlib/RingTheory/Ideal/Prime.lean b/Mathlib/RingTheory/Ideal/Prime.lean index 321e1b9b104eb..afb9e63f85dcf 100644 --- a/Mathlib/RingTheory/Ideal/Prime.lean +++ b/Mathlib/RingTheory/Ideal/Prime.lean @@ -3,7 +3,6 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Chris Hughes, Mario Carneiro -/ -import Mathlib.Algebra.Ring.Regular import Mathlib.RingTheory.Ideal.Lattice /-! diff --git a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean index 8d8291b64c232..488ffed5743b2 100644 --- a/Mathlib/RingTheory/Ideal/Quotient/Operations.lean +++ b/Mathlib/RingTheory/Ideal/Quotient/Operations.lean @@ -590,9 +590,21 @@ def quotientEquivAlg (I : Ideal A) (J : Ideal B) (f : A ≃ₐ[R₁] B) (hIJ : J end +/-- If `P` lies over `p`, then `R / p` has a canonical map to `A / P`. -/ +abbrev Quotient.algebraQuotientOfLEComap [Algebra R A] {p : Ideal R} {P : Ideal A} + (h : p ≤ comap (algebraMap R A) P) : Algebra (R ⧸ p) (A ⧸ P) where + toRingHom := quotientMap P (algebraMap R A) h + smul := Quotient.lift₂ (⟦· • ·⟧) fun r₁ a₁ r₂ a₂ hr ha ↦ Quotient.sound <| by + have := h (p.quotientRel_def.mp hr) + rw [mem_comap, map_sub] at this + simpa only [Algebra.smul_def] using P.quotientRel_def.mpr + (P.mul_sub_mul_mem this <| P.quotientRel_def.mp ha) + smul_def' := by rintro ⟨_⟩ ⟨_⟩; exact congr_arg (⟦·⟧) (Algebra.smul_def _ _) + commutes' := by rintro ⟨_⟩ ⟨_⟩; exact congr_arg (⟦·⟧) (Algebra.commutes _ _) + instance (priority := 100) quotientAlgebra {I : Ideal A} [Algebra R A] : Algebra (R ⧸ I.comap (algebraMap R A)) (A ⧸ I) := - (quotientMap I (algebraMap R A) (le_of_eq rfl)).toAlgebra + Quotient.algebraQuotientOfLEComap le_rfl theorem algebraMap_quotient_injective {I : Ideal A} [Algebra R A] : Function.Injective (algebraMap (R ⧸ I.comap (algebraMap R A)) (A ⧸ I)) := by diff --git a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean index 1c84755bf4e23..b820b75229efd 100644 --- a/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean +++ b/Mathlib/RingTheory/IntegralClosure/IntegralRestrict.lean @@ -28,10 +28,12 @@ open 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] + [IsIntegralClosure B A L] section galois +variable [Algebra.IsAlgebraic K L] + /-- The lift `End(B/A) → End(L/K)` in an ALKB setup. This is inverse to the restriction. See `galRestrictHom`. -/ noncomputable @@ -114,7 +116,9 @@ 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) +end galois + +variable [FiniteDimensional K L] lemma prod_galRestrict_eq_norm [IsGalois K L] [IsIntegrallyClosed A] (x : B) : (∏ σ : L ≃ₐ[K] L, galRestrict A K L B σ x) = @@ -125,8 +129,6 @@ lemma prod_galRestrict_eq_norm [IsGalois K L] [IsIntegrallyClosed A] (x : B) : simp only [map_prod, algebraMap_galRestrict_apply, IsIntegralClosure.algebraMap_mk', Algebra.norm_eq_prod_automorphisms, AlgHom.coe_coe, RingHom.coe_comp, Function.comp_apply] -end galois - attribute [local instance] FractionRing.liftAlgebra FractionRing.isScalarTower_liftAlgebra noncomputable diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean index e95d736928d15..a8b4fdf450893 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegral/Basic.lean @@ -5,6 +5,7 @@ Authors: Kenny Lau -/ import Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs import Mathlib.Algebra.Polynomial.Expand +import Mathlib.RingTheory.Adjoin.Polynomial import Mathlib.RingTheory.Finiteness.Subalgebra import Mathlib.RingTheory.Polynomial.Tower @@ -100,9 +101,14 @@ theorem isIntegral_one [Algebra R B] : IsIntegral R (1 : B) := variable (f : R →+* S) theorem IsIntegral.of_pow [Algebra R B] {x : B} {n : ℕ} (hn : 0 < n) (hx : IsIntegral R <| x ^ n) : - IsIntegral R x := by - rcases hx with ⟨p, hmonic, heval⟩ - exact ⟨expand R n p, hmonic.expand hn, by rwa [← aeval_def, expand_aeval]⟩ + IsIntegral R x := + have ⟨p, hmonic, heval⟩ := hx + ⟨expand R n p, hmonic.expand hn, by rwa [← aeval_def, expand_aeval]⟩ + +theorem IsIntegral.of_aeval_monic {x : A} {p : R[X]} (monic : p.Monic) + (deg : p.natDegree ≠ 0) (hx : IsIntegral R (aeval x p)) : IsIntegral R x := + have ⟨p, hmonic, heval⟩ := hx + ⟨_, hmonic.comp monic deg, by rwa [eval₂_comp, ← aeval_def x]⟩ end diff --git a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean index 1cc2210dce70f..17251c27433cb 100644 --- a/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean +++ b/Mathlib/RingTheory/IntegralClosure/IsIntegralClosure/Basic.lean @@ -8,6 +8,7 @@ import Mathlib.LinearAlgebra.FiniteDimensional.Defs import Mathlib.RingTheory.IntegralClosure.IsIntegralClosure.Defs import Mathlib.RingTheory.IntegralClosure.Algebra.Basic import Mathlib.RingTheory.FiniteType +import Mathlib.RingTheory.Polynomial.IntegralNormalization import Mathlib.RingTheory.Polynomial.ScaleRoots /-! @@ -262,81 +263,39 @@ section variable (p : R[X]) (x : S) /-- The monic polynomial whose roots are `p.leadingCoeff * x` for roots `x` of `p`. -/ -noncomputable def normalizeScaleRoots (p : R[X]) : R[X] := - ∑ i ∈ p.support, - monomial i (if i = p.natDegree then 1 else p.coeff i * p.leadingCoeff ^ (p.natDegree - 1 - i)) - -theorem normalizeScaleRoots_coeff_mul_leadingCoeff_pow (i : ℕ) (hp : 1 ≤ natDegree p) : - (normalizeScaleRoots p).coeff i * p.leadingCoeff ^ i = - p.coeff i * p.leadingCoeff ^ (p.natDegree - 1) := by - simp only [normalizeScaleRoots, finset_sum_coeff, coeff_monomial, Finset.sum_ite_eq', one_mul, - zero_mul, mem_support_iff, ite_mul, Ne, ite_not] - split_ifs with h₁ h₂ - · simp [h₁] - · rw [h₂, leadingCoeff, ← pow_succ', tsub_add_cancel_of_le hp] - · rw [mul_assoc, ← pow_add, tsub_add_cancel_of_le] - apply Nat.le_sub_one_of_lt - rw [lt_iff_le_and_ne] - exact ⟨le_natDegree_of_ne_zero h₁, h₂⟩ - -theorem leadingCoeff_smul_normalizeScaleRoots (p : R[X]) : - p.leadingCoeff • normalizeScaleRoots p = scaleRoots p p.leadingCoeff := by - ext - simp only [coeff_scaleRoots, normalizeScaleRoots, coeff_monomial, coeff_smul, Finset.smul_sum, - Ne, Finset.sum_ite_eq', finset_sum_coeff, smul_ite, smul_zero, mem_support_iff] - -- Porting note: added the following `simp only` - simp only [tsub_le_iff_right, smul_eq_mul, mul_ite, mul_one, mul_zero, - Finset.sum_ite_eq', mem_support_iff, ne_eq, ite_not] - split_ifs with h₁ h₂ - · simp [*] - · simp [*] - · rw [mul_comm, mul_assoc, ← pow_succ, tsub_right_comm, - tsub_add_cancel_of_le] - rw [Nat.succ_le_iff] - exact tsub_pos_of_lt (lt_of_le_of_ne (le_natDegree_of_ne_zero h₁) h₂) - -theorem normalizeScaleRoots_support : (normalizeScaleRoots p).support ≤ p.support := by - intro x - contrapose - simp only [not_mem_support_iff, normalizeScaleRoots, finset_sum_coeff, coeff_monomial, - Finset.sum_ite_eq', mem_support_iff, Ne, Classical.not_not, ite_eq_right_iff] - intro h₁ h₂ - exact (h₂ h₁).elim - -theorem normalizeScaleRoots_degree : (normalizeScaleRoots p).degree = p.degree := by - apply le_antisymm - · exact Finset.sup_mono (normalizeScaleRoots_support p) - · rw [← degree_scaleRoots, ← leadingCoeff_smul_normalizeScaleRoots] - exact degree_smul_le _ _ - -theorem normalizeScaleRoots_eval₂_leadingCoeff_mul (h : 1 ≤ p.natDegree) (f : R →+* S) (x : S) : - (normalizeScaleRoots p).eval₂ f (f p.leadingCoeff * x) = - f p.leadingCoeff ^ (p.natDegree - 1) * p.eval₂ f x := by - rw [eval₂_eq_sum_range, eval₂_eq_sum_range, Finset.mul_sum] - apply Finset.sum_congr - · rw [natDegree_eq_of_degree_eq (normalizeScaleRoots_degree p)] - intro n _hn - rw [mul_pow, ← mul_assoc, ← f.map_pow, ← f.map_mul, - normalizeScaleRoots_coeff_mul_leadingCoeff_pow _ _ h, f.map_mul, f.map_pow] - ring - -theorem normalizeScaleRoots_monic (h : p ≠ 0) : (normalizeScaleRoots p).Monic := by - delta Monic leadingCoeff - rw [natDegree_eq_of_degree_eq (normalizeScaleRoots_degree p)] - suffices p = 0 → (0 : R) = 1 by simpa [normalizeScaleRoots, coeff_monomial] - exact fun h' => (h h').elim +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots := integralNormalization + +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots_coeff_mul_leadingCoeff_pow := + integralNormalization_coeff_mul_leadingCoeff_pow + +@[deprecated (since := "2024-11-30")] +alias leadingCoeff_smul_normalizeScaleRoots := leadingCoeff_smul_integralNormalization + +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots_support := support_integralNormalization_subset + +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots_degree := integralNormalization_degree + +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots_eval₂_leadingCoeff_mul := integralNormalization_eval₂_leadingCoeff_mul + +@[deprecated (since := "2024-11-30")] +alias normalizeScaleRoots_monic := monic_integralNormalization /-- Given a `p : R[X]` and a `x : S` such that `p.eval₂ f x = 0`, `f p.leadingCoeff * x` is integral. -/ theorem RingHom.isIntegralElem_leadingCoeff_mul (h : p.eval₂ f x = 0) : f.IsIntegralElem (f p.leadingCoeff * x) := by by_cases h' : 1 ≤ p.natDegree - · use normalizeScaleRoots p + · use integralNormalization p have : p ≠ 0 := fun h'' => by rw [h'', natDegree_zero] at h' exact Nat.not_succ_le_zero 0 h' - use normalizeScaleRoots_monic p this - rw [normalizeScaleRoots_eval₂_leadingCoeff_mul p h' f x, h, mul_zero] + use monic_integralNormalization this + rw [integralNormalization_eval₂_leadingCoeff_mul h' f x, h, mul_zero] · by_cases hp : p.map f = 0 · apply_fun fun q => coeff q p.natDegree at hp rw [coeff_map, coeff_zero, coeff_natDegree] at hp diff --git a/Mathlib/RingTheory/IsTensorProduct.lean b/Mathlib/RingTheory/IsTensorProduct.lean index 292d28691d254..1023fe388ff81 100644 --- a/Mathlib/RingTheory/IsTensorProduct.lean +++ b/Mathlib/RingTheory/IsTensorProduct.lean @@ -3,8 +3,9 @@ Copyright (c) 2022 Andrew Yang. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ -import Mathlib.RingTheory.TensorProduct.Basic import Mathlib.Algebra.Module.ULift +import Mathlib.RingTheory.TensorProduct.Basic +import Mathlib.Tactic.Ring /-! # The characteristic predicate of tensor product @@ -333,7 +334,7 @@ lemma IsBaseChange.of_comp {f : M →ₗ[R] N} (hf : IsBaseChange S f) {h : N let q : O →ₗ[T] Q := hc.lift r' refine ⟨q, ?_, ?_⟩ · apply hf.algHom_ext' - simp [LinearMap.comp_assoc, hc.lift_comp] + simp [r', q, LinearMap.comp_assoc, hc.lift_comp] · intro q' hq' apply hc.algHom_ext' apply_fun LinearMap.restrictScalars R at hq' @@ -389,7 +390,7 @@ theorem Algebra.IsPushout.symm (h : Algebra.IsPushout R S R' S') : Algebra.IsPus (toAlgHom R S S').toLinearMap = (e.toLinearMap.restrictScalars R).comp (TensorProduct.mk R R' S 1) := by ext - simp [h.1.equiv_tmul, Algebra.smul_def] + simp [e, h.1.equiv_tmul, Algebra.smul_def] constructor rw [this] exact (TensorProduct.isBaseChange R S R').comp (IsBaseChange.ofEquiv e) diff --git a/Mathlib/RingTheory/JacobsonIdeal.lean b/Mathlib/RingTheory/Jacobson/Ideal.lean similarity index 86% rename from Mathlib/RingTheory/JacobsonIdeal.lean rename to Mathlib/RingTheory/Jacobson/Ideal.lean index 804cf08cea5f3..181f68bbf0591 100644 --- a/Mathlib/RingTheory/JacobsonIdeal.lean +++ b/Mathlib/RingTheory/Jacobson/Ideal.lean @@ -4,8 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Devon Tuma, Wojciech Nawrocki -/ import Mathlib.RingTheory.Ideal.IsPrimary -import Mathlib.RingTheory.Ideal.Quotient.Basic -import Mathlib.RingTheory.Polynomial.Quotient +import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.TwoSidedIdeal.Operations /-! @@ -52,8 +51,6 @@ namespace Ideal variable {R : Type u} {S : Type v} -open Polynomial - section Jacobson section Ring @@ -99,8 +96,7 @@ theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x let ⟨p, hpi, q, hq, hpq⟩ := Submodule.mem_sup.1 ((eq_top_iff_one _).1 hxy) let ⟨r, hr⟩ := mem_span_singleton'.1 hq ⟨r, by - -- Porting note: supply `mul_add_one` with explicit variables - rw [mul_assoc, ← mul_add_one r (y * x), hr, ← hpq, ← neg_sub, add_sub_cancel_right] + rw [mul_assoc, ← mul_add_one, hr, ← hpq, ← neg_sub, add_sub_cancel_right] exact I.neg_mem hpi⟩) fun hxy : I ⊔ span {y * x + 1} ≠ ⊤ => let ⟨M, hm1, hm2⟩ := exists_le_maximal _ hxy suffices x ∉ M from (this <| mem_sInf.1 hx ⟨le_trans le_sup_left hm2, hm1⟩).elim @@ -111,8 +107,7 @@ theorem mem_jacobson_iff {x : R} : x ∈ jacobson I ↔ ∀ y, ∃ z, z * y * x let ⟨z, hz⟩ := hx (-y) hm.1.1 <| (eq_top_iff_one _).2 <| sub_sub_cancel (z * -y * x + z) 1 ▸ M.sub_mem (by - -- Porting note: supply `mul_add_one` with explicit variables - rw [mul_assoc, ← mul_add_one z, neg_mul, ← sub_eq_iff_eq_add.mpr df.symm, neg_sub, + rw [mul_assoc, ← mul_add_one, neg_mul, ← sub_eq_iff_eq_add.mpr df.symm, neg_sub, sub_add_cancel] exact M.mul_mem_left _ hi) <| him hz⟩ @@ -160,15 +155,15 @@ theorem eq_jacobson_iff_sInf_maximal' : /-- An ideal `I` equals its Jacobson radical if and only if every element outside `I` also lies outside of a maximal ideal containing `I`. -/ theorem eq_jacobson_iff_not_mem : - I.jacobson = I ↔ ∀ (x) (_ : x ∉ I), ∃ M : Ideal R, (I ≤ M ∧ M.IsMaximal) ∧ x ∉ M := by + I.jacobson = I ↔ ∀ x ∉ I, ∃ M : Ideal R, (I ≤ M ∧ M.IsMaximal) ∧ x ∉ M := by constructor · intro h x hx - erw [← h, mem_sInf] at hx + rw [← h, Ideal.jacobson, mem_sInf] at hx push_neg at hx exact hx · refine fun h => le_antisymm (fun x hx => ?_) le_jacobson contrapose hx - erw [mem_sInf] + rw [Ideal.jacobson, mem_sInf] push_neg exact h x hx @@ -338,45 +333,6 @@ end CommRing end Jacobson -section Polynomial - -open Polynomial - -variable [CommRing R] - -theorem jacobson_bot_polynomial_le_sInf_map_maximal : - jacobson (⊥ : Ideal R[X]) ≤ sInf (map (C : R →+* R[X]) '' { J : Ideal R | J.IsMaximal }) := by - refine le_sInf fun J => exists_imp.2 fun j hj => ?_ - haveI : j.IsMaximal := hj.1 - refine Trans.trans (jacobson_mono bot_le) (le_of_eq ?_ : J.jacobson ≤ J) - suffices t : (⊥ : Ideal (Polynomial (R ⧸ j))).jacobson = ⊥ by - rw [← hj.2, jacobson_eq_iff_jacobson_quotient_eq_bot] - replace t := congr_arg (map (polynomialQuotientEquivQuotientPolynomial j).toRingHom) t - rwa [map_jacobson_of_bijective _, map_bot] at t - exact RingEquiv.bijective (polynomialQuotientEquivQuotientPolynomial j) - refine eq_bot_iff.2 fun f hf => ?_ - have r1 : (X : (R ⧸ j)[X]) ≠ 0 := fun hX => by - replace hX := congr_arg (fun f => coeff f 1) hX - simp only [coeff_X_one, coeff_zero] at hX - exact zero_ne_one hX.symm - have r2 := eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit ((mem_jacobson_bot.1 hf) X)) - simp only [coeff_add, mul_coeff_zero, coeff_X_zero, mul_zero, coeff_one_zero, zero_add] at r2 - erw [add_left_eq_self] at r2 - simpa using (mul_eq_zero.mp r2).resolve_right r1 - -- Porting note: this is golfed to much - -- simpa [(fun hX => by simpa using congr_arg (fun f => coeff f 1) hX : (X : (R ⧸ j)[X]) ≠ 0)] - -- using eq_C_of_degree_eq_zero (degree_eq_zero_of_is_unit ((mem_jacobson_bot.1 hf) X)) - -theorem jacobson_bot_polynomial_of_jacobson_bot (h : jacobson (⊥ : Ideal R) = ⊥) : - jacobson (⊥ : Ideal R[X]) = ⊥ := by - refine eq_bot_iff.2 (le_trans jacobson_bot_polynomial_le_sInf_map_maximal ?_) - refine fun f hf => (Submodule.mem_bot R[X]).2 <| Polynomial.ext fun n => - Trans.trans (?_ : coeff f n = 0) (coeff_zero n).symm - suffices f.coeff n ∈ Ideal.jacobson ⊥ by rwa [h, Submodule.mem_bot] at this - exact mem_sInf.2 fun j hj => (mem_map_C_iff.1 ((mem_sInf.1 hf) ⟨j, ⟨hj.2, rfl⟩⟩)) n - -end Polynomial - section IsLocal variable [CommRing R] diff --git a/Mathlib/RingTheory/Jacobson/Polynomial.lean b/Mathlib/RingTheory/Jacobson/Polynomial.lean new file mode 100644 index 0000000000000..c102d0db7133b --- /dev/null +++ b/Mathlib/RingTheory/Jacobson/Polynomial.lean @@ -0,0 +1,45 @@ +/- +Copyright (c) 2020 Devon Tuma. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Devon Tuma +-/ +import Mathlib.RingTheory.Jacobson.Ideal +import Mathlib.RingTheory.Polynomial.Quotient +/-! +# Jacobson radical of polynomial ring + +-/ + +namespace Ideal + +section Polynomial + +open Polynomial + +variable {R : Type*} [CommRing R] + +theorem jacobson_bot_polynomial_le_sInf_map_maximal : + jacobson (⊥ : Ideal R[X]) ≤ sInf (map (C : R →+* R[X]) '' { J : Ideal R | J.IsMaximal }) := by + refine le_sInf fun J => exists_imp.2 fun j hj => ?_ + haveI : j.IsMaximal := hj.1 + refine Trans.trans (jacobson_mono bot_le) (le_of_eq ?_ : J.jacobson ≤ J) + suffices t : (⊥ : Ideal (Polynomial (R ⧸ j))).jacobson = ⊥ by + rw [← hj.2, jacobson_eq_iff_jacobson_quotient_eq_bot] + replace t := congr_arg (map (polynomialQuotientEquivQuotientPolynomial j).toRingHom) t + rwa [map_jacobson_of_bijective _, map_bot] at t + exact RingEquiv.bijective (polynomialQuotientEquivQuotientPolynomial j) + refine eq_bot_iff.2 fun f hf => ?_ + have r1 : (X : (R ⧸ j)[X]) ≠ 0 := ne_of_apply_ne (coeff · 1) <| by simp + simpa [r1] using eq_C_of_degree_eq_zero (degree_eq_zero_of_isUnit ((mem_jacobson_bot.1 hf) X)) + +theorem jacobson_bot_polynomial_of_jacobson_bot (h : jacobson (⊥ : Ideal R) = ⊥) : + jacobson (⊥ : Ideal R[X]) = ⊥ := by + refine eq_bot_iff.2 (le_trans jacobson_bot_polynomial_le_sInf_map_maximal ?_) + refine fun f hf => (Submodule.mem_bot R[X]).2 <| Polynomial.ext fun n => + Trans.trans (?_ : coeff f n = 0) (coeff_zero n).symm + suffices f.coeff n ∈ Ideal.jacobson ⊥ by rwa [h, Submodule.mem_bot] at this + exact mem_sInf.2 fun j hj => (mem_map_C_iff.1 ((mem_sInf.1 hf) ⟨j, ⟨hj.2, rfl⟩⟩)) n + +end Polynomial + +end Ideal diff --git a/Mathlib/RingTheory/Jacobson.lean b/Mathlib/RingTheory/Jacobson/Ring.lean similarity index 99% rename from Mathlib/RingTheory/Jacobson.lean rename to Mathlib/RingTheory/Jacobson/Ring.lean index 56997e889c66f..958012570ae25 100644 --- a/Mathlib/RingTheory/Jacobson.lean +++ b/Mathlib/RingTheory/Jacobson/Ring.lean @@ -5,7 +5,7 @@ Authors: Devon Tuma -/ import Mathlib.RingTheory.Localization.Away.Basic import Mathlib.RingTheory.Ideal.Over -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Polynomial import Mathlib.RingTheory.Artinian /-! @@ -492,7 +492,7 @@ theorem isMaximal_comap_C_of_isMaximal [IsJacobsonRing R] [Nontrivial R] rw [(map_bot.symm : (⊥ : Ideal (Localization M')) = Ideal.map (algebraMap (R[X] ⧸ P) (Localization M')) ⊥)] let bot_maximal := (bot_quotient_isMaximal_iff _).mpr hP - refine map.isMaximal (algebraMap (R[X] ⧸ P) (Localization M')) ?_ bot_maximal + refine bot_maximal.map_bijective (algebraMap (R[X] ⧸ P) (Localization M')) ?_ apply IsField.localization_map_bijective hM' rwa [← Quotient.maximal_ideal_iff_isField_quotient, ← bot_quotient_isMaximal_iff] @@ -702,7 +702,12 @@ lemma finite_of_finite_type_of_isJacobsonRing (R S : Type*) [CommRing R] [Field obtain ⟨ι, hι, f, hf⟩ := Algebra.FiniteType.iff_quotient_mvPolynomial'.mp ‹_› have : (algebraMap R S).IsIntegral := by rw [← f.comp_algebraMap] - exact MvPolynomial.comp_C_integral_of_surjective_of_isJacobsonRing f hf + #adaptation_note + /-- + After https://github.com/leanprover/lean4/pull/6024 + we needed to write `f.toRingHom` instead of just `f`, to avoid unification issues. + -/ + exact MvPolynomial.comp_C_integral_of_surjective_of_isJacobsonRing f.toRingHom hf have : Algebra.IsIntegral R S := Algebra.isIntegral_def.mpr this exact Algebra.IsIntegral.finite diff --git a/Mathlib/RingTheory/Kaehler/Basic.lean b/Mathlib/RingTheory/Kaehler/Basic.lean index 96de1da9e85a4..d668bcecc861a 100644 --- a/Mathlib/RingTheory/Kaehler/Basic.lean +++ b/Mathlib/RingTheory/Kaehler/Basic.lean @@ -259,7 +259,7 @@ def Derivation.liftKaehlerDifferential (D : Derivation R S M) : Ω[S⁄R] →ₗ · exact D.tensorProductTo.comp ((KaehlerDifferential.ideal R S).subtype.restrictScalars S) · intro x hx rw [LinearMap.mem_ker] - refine Submodule.smul_induction_on hx ?_ ?_ + refine Submodule.smul_induction_on ((Submodule.restrictScalars_mem _ _ _).mp hx) ?_ ?_ · rintro x hx y - rw [RingHom.mem_ker] at hx dsimp @@ -839,7 +839,8 @@ theorem KaehlerDifferential.range_kerCotangentToTensor constructor · rintro ⟨x, rfl⟩ obtain ⟨x, rfl⟩ := Ideal.toCotangent_surjective _ x - simp [kerCotangentToTensor_toCotangent, RingHom.mem_ker.mp x.2] + simp only [kerCotangentToTensor_toCotangent, Submodule.restrictScalars_mem, LinearMap.mem_ker, + mapBaseChange_tmul, map_D, RingHom.mem_ker.mp x.2, map_zero, smul_zero] · intro hx obtain ⟨x, rfl⟩ := LinearMap.rTensor_surjective (Ω[A⁄R]) (g := Algebra.linearMap A B) h x obtain ⟨x, rfl⟩ := (TensorProduct.lid _ _).symm.surjective x @@ -869,6 +870,8 @@ theorem KaehlerDifferential.range_kerCotangentToTensor simp [RingHom.mem_ker, ha, this.2] · simp only [map_sum, LinearMapClass.map_smul, kerCotangentToTensor_toCotangent, map_sub] simp_rw [← TensorProduct.tmul_smul] + -- was `simp [kerCotangentToTensor_toCotangent, RingHom.mem_ker.mp x.2]` and very slow + -- (https://github.com/leanprover-community/mathlib4/issues/19751) simp only [smul_sub, TensorProduct.tmul_sub, Finset.sum_sub_distrib, ← TensorProduct.tmul_sum, ← Finset.sum_smul, Finset.sum_attach, sub_eq_self, Finset.sum_attach (f := fun i ↦ x i • KaehlerDifferential.D R A i)] diff --git a/Mathlib/RingTheory/LocalProperties/Projective.lean b/Mathlib/RingTheory/LocalProperties/Projective.lean index d6c0268663ed7..bf3d45d29deed 100644 --- a/Mathlib/RingTheory/LocalProperties/Projective.lean +++ b/Mathlib/RingTheory/LocalProperties/Projective.lean @@ -95,7 +95,7 @@ theorem LinearMap.split_surjective_of_localization_maximal conv_lhs => rw [← LinearMap.map_smul_of_tower] rw [← Submonoid.smul_def, IsLocalizedModule.mk'_cancel', IsLocalizedModule.mk'_cancel'] apply LinearMap.restrictScalars_injective R - apply IsLocalizedModule.ringHom_ext I.primeCompl (LocalizedModule.mkLinearMap I.primeCompl N) + apply IsLocalizedModule.ext I.primeCompl (LocalizedModule.mkLinearMap I.primeCompl N) · exact IsLocalizedModule.map_units (LocalizedModule.mkLinearMap I.primeCompl N) ext simp only [LocalizedModule.map_mk, LinearMap.coe_comp, LinearMap.coe_restrictScalars, @@ -111,7 +111,7 @@ theorem LinearMap.split_surjective_of_localization_maximal simp only [Module.algebraMap_end_apply, ← Submonoid.smul_def, IsLocalizedModule.mk'_cancel', ← LinearMap.map_smul_of_tower] apply LinearMap.restrictScalars_injective R - apply IsLocalizedModule.ringHom_ext I.primeCompl (LocalizedModule.mkLinearMap I.primeCompl N) + apply IsLocalizedModule.ext I.primeCompl (LocalizedModule.mkLinearMap I.primeCompl N) · exact IsLocalizedModule.map_units (LocalizedModule.mkLinearMap I.primeCompl N) ext simp only [coe_comp, coe_restrictScalars, Function.comp_apply, diff --git a/Mathlib/RingTheory/LocalRing/Basic.lean b/Mathlib/RingTheory/LocalRing/Basic.lean index ff066f8280c34..48a98a6d9adb0 100644 --- a/Mathlib/RingTheory/LocalRing/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/Basic.lean @@ -16,11 +16,11 @@ We prove basic properties of local rings. variable {R S : Type*} -section CommSemiring +namespace IsLocalRing -variable [CommSemiring R] +section Semiring -namespace IsLocalRing +variable [Semiring R] theorem of_isUnit_or_isUnit_of_isUnit_add [Nontrivial R] (h : ∀ a b : R, IsUnit (a + b) → IsUnit a ∨ IsUnit b) : IsLocalRing R := @@ -28,8 +28,15 @@ theorem of_isUnit_or_isUnit_of_isUnit_add [Nontrivial R] /-- A semiring is local if it is nontrivial and the set of nonunits is closed under the addition. -/ theorem of_nonunits_add [Nontrivial R] - (h : ∀ a b : R, a ∈ nonunits R → b ∈ nonunits R → a + b ∈ nonunits R) : IsLocalRing R := - ⟨fun {a b} hab => or_iff_not_and_not.2 fun H => h a b H.1 H.2 <| hab.symm ▸ isUnit_one⟩ + (h : ∀ a b : R, a ∈ nonunits R → b ∈ nonunits R → a + b ∈ nonunits R) : IsLocalRing R where + isUnit_or_isUnit_of_add_one {a b} hab := + or_iff_not_and_not.2 fun H => h a b H.1 H.2 <| hab.symm ▸ isUnit_one + +end Semiring + +section CommSemiring + +variable [CommSemiring R] /-- A semiring is local if it has a unique maximal ideal. -/ theorem of_unique_max_ideal (h : ∃! I : Ideal R, I.IsMaximal) : IsLocalRing R := @@ -65,8 +72,6 @@ theorem isUnit_or_isUnit_of_isUnit_add {a b : R} (h : IsUnit (a + b)) : IsUnit a theorem nonunits_add {a b : R} (ha : a ∈ nonunits R) (hb : b ∈ nonunits R) : a + b ∈ nonunits R := fun H => not_or_intro ha hb (isUnit_or_isUnit_of_isUnit_add H) -end IsLocalRing - @[deprecated (since := "2024-11-11")] alias LocalRing.of_isUnit_or_isUnit_of_isUnit_add := IsLocalRing.of_isUnit_or_isUnit_of_isUnit_add @@ -87,15 +92,19 @@ alias LocalRing.nonunits_add := IsLocalRing.nonunits_add end CommSemiring -namespace IsLocalRing +section Ring -variable [CommRing R] +variable [Ring R] theorem of_isUnit_or_isUnit_one_sub_self [Nontrivial R] (h : ∀ a : R, IsUnit a ∨ IsUnit (1 - a)) : IsLocalRing R := ⟨fun {a b} hab => add_sub_cancel_left a b ▸ hab.symm ▸ h a⟩ -variable [IsLocalRing R] +end Ring + +section CommRing + +variable [CommRing R] [IsLocalRing R] theorem isUnit_or_isUnit_one_sub_self (a : R) : IsUnit a ∨ IsUnit (1 - a) := isUnit_or_isUnit_of_isUnit_add <| (add_sub_cancel a 1).symm ▸ isUnit_one @@ -106,7 +115,7 @@ theorem isUnit_of_mem_nonunits_one_sub_self (a : R) (h : 1 - a ∈ nonunits R) : theorem isUnit_one_sub_self_of_mem_nonunits (a : R) (h : a ∈ nonunits R) : IsUnit (1 - a) := or_iff_not_imp_left.1 (isUnit_or_isUnit_one_sub_self a) h -theorem of_surjective' [CommRing S] [Nontrivial S] (f : R →+* S) (hf : Function.Surjective f) : +theorem of_surjective' [Ring S] [Nontrivial S] (f : R →+* S) (hf : Function.Surjective f) : IsLocalRing S := of_isUnit_or_isUnit_one_sub_self (by intro b @@ -132,6 +141,8 @@ alias LocalRing.isUnit_one_sub_self_of_mem_nonunits := @[deprecated (since := "2024-11-11")] alias LocalRing.of_surjective' := IsLocalRing.of_surjective' +end CommRing + end IsLocalRing namespace Field diff --git a/Mathlib/RingTheory/LocalRing/MaximalIdeal/Basic.lean b/Mathlib/RingTheory/LocalRing/MaximalIdeal/Basic.lean index 2a707385da691..1919f202cbf8f 100644 --- a/Mathlib/RingTheory/LocalRing/MaximalIdeal/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/MaximalIdeal/Basic.lean @@ -3,7 +3,7 @@ Copyright (c) 2018 Kenny Lau. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kenny Lau, Chris Hughes, Mario Carneiro -/ -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Ideal import Mathlib.RingTheory.LocalRing.MaximalIdeal.Defs import Mathlib.RingTheory.Localization.Basic import Mathlib.RingTheory.Nilpotent.Lemmas diff --git a/Mathlib/RingTheory/LocalRing/Module.lean b/Mathlib/RingTheory/LocalRing/Module.lean index 6239fe6f8a670..40aa2ebe664c3 100644 --- a/Mathlib/RingTheory/LocalRing/Module.lean +++ b/Mathlib/RingTheory/LocalRing/Module.lean @@ -4,12 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang -/ import Mathlib.Algebra.Module.FinitePresentation -import Mathlib.LinearAlgebra.FiniteDimensional +import Mathlib.LinearAlgebra.Dual import Mathlib.RingTheory.FiniteType import Mathlib.RingTheory.Flat.Basic import Mathlib.RingTheory.LocalRing.ResidueField.Basic import Mathlib.RingTheory.Nakayama -import Mathlib.RingTheory.TensorProduct.Free +import Mathlib.Algebra.Module.Torsion /-! # Finite modules over local rings diff --git a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean index ad680a8c1d695..cf35586f78472 100644 --- a/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/ResidueField/Basic.lean @@ -164,9 +164,6 @@ variable [Algebra R S] [IsLocalHom (algebraMap R S)] noncomputable instance : Algebra (ResidueField R) (ResidueField S) := (ResidueField.map (algebraMap R S)).toAlgebra -noncomputable instance : Algebra R (ResidueField S) := - ((ResidueField.map <| algebraMap R S).comp <| residue R).toAlgebra - instance : IsScalarTower R (ResidueField R) (ResidueField S) := IsScalarTower.of_algebraMap_eq (congrFun rfl) @@ -176,7 +173,6 @@ instance finiteDimensional_of_noetherian [IsNoetherian R S] : isNoetherian_of_tower R (S := ResidueField R) (M := ResidueField S) _ convert isNoetherian_of_surjective S (Ideal.Quotient.mkₐ R (maximalIdeal S)).toLinearMap (LinearMap.range_eq_top.mpr Ideal.Quotient.mk_surjective) - exact Algebra.algebra_ext _ _ (fun r => rfl) -- We want to be able to refer to `hfin` set_option linter.unusedVariables false in diff --git a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean index fa149868d151e..0546a5cd3fb8e 100644 --- a/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean +++ b/Mathlib/RingTheory/LocalRing/RingHom/Basic.lean @@ -55,7 +55,7 @@ alias isLocalRingHom_of_comp := isLocalHom_of_comp /-- If `f : R →+* S` is a local ring hom, then `R` is a local ring if `S` is. -/ theorem RingHom.domain_isLocalRing {R S : Type*} [CommSemiring R] [CommSemiring S] [IsLocalRing S] (f : R →+* S) [IsLocalHom f] : IsLocalRing R := by - haveI : Nontrivial R := pullback_nonzero f f.map_zero f.map_one + haveI : Nontrivial R := f.domain_nontrivial apply IsLocalRing.of_nonunits_add intro a b simp_rw [← map_mem_nonunits_iff f, f.map_add] diff --git a/Mathlib/RingTheory/LocalRing/Subring.lean b/Mathlib/RingTheory/LocalRing/Subring.lean index bafa2eb662812..90d074bc764e8 100644 --- a/Mathlib/RingTheory/LocalRing/Subring.lean +++ b/Mathlib/RingTheory/LocalRing/Subring.lean @@ -18,9 +18,6 @@ import Mathlib.RingTheory.Localization.AtPrime open IsLocalRing Set -open scoped Polynomial - - variable {R S : Type*} [CommRing R] [CommRing S] variable {K : Type*} [Field K] diff --git a/Mathlib/RingTheory/Localization/AtPrime.lean b/Mathlib/RingTheory/Localization/AtPrime.lean index 1337c943de11e..e8d94b851a13e 100644 --- a/Mathlib/RingTheory/Localization/AtPrime.lean +++ b/Mathlib/RingTheory/Localization/AtPrime.lean @@ -249,24 +249,27 @@ theorem localRingHom_comp {S : Type*} [CommSemiring S] (J : Ideal S) [hJ : J.IsP localRingHom_unique _ _ _ _ fun r => by simp only [Function.comp_apply, RingHom.coe_comp, localRingHom_to_map] -end Localization +namespace AtPrime + +variable {ι : Type*} {R : ι → Type*} [∀ i, CommSemiring (R i)] +variable {i : ι} (I : Ideal (R i)) [I.IsPrime] -namespace RingHom +/-- `Localization.localRingHom` specialized to a projection homomorphism from a product ring. -/ +noncomputable abbrev mapPiEvalRingHom : + Localization.AtPrime (I.comap <| Pi.evalRingHom R i) →+* Localization.AtPrime I := + localRingHom _ _ _ rfl -variable (R) +theorem mapPiEvalRingHom_bijective : Function.Bijective (mapPiEvalRingHom I) := + Localization.mapPiEvalRingHom_bijective _ -/-- The canonical ring homomorphism from a commutative semiring to the product of its -localizations at all maximal ideals. It is always injective. -/ -def toLocalizationIsMaximal : R →+* - Π I : {I : Ideal R // I.IsMaximal}, haveI : I.1.IsMaximal := I.2; Localization.AtPrime I.1 := - Pi.ringHom fun _ ↦ algebraMap R _ +theorem mapPiEvalRingHom_comp_algebraMap : + (mapPiEvalRingHom I).comp (algebraMap _ _) = (algebraMap _ _).comp (Pi.evalRingHom R i) := + IsLocalization.map_comp _ -theorem toLocalizationIsMaximal_injective : - Function.Injective (RingHom.toLocalizationIsMaximal R) := fun r r' eq ↦ by - rw [← one_mul r, ← one_mul r'] - by_contra ne - have ⟨I, mI, hI⟩ := (Module.eqIdeal R r r').exists_le_maximal ((Ideal.ne_top_iff_one _).mpr ne) - have ⟨s, hs⟩ := (IsLocalization.eq_iff_exists I.primeCompl _).mp (congr_fun eq ⟨I, mI⟩) - exact s.2 (hI hs) +theorem mapPiEvalRingHom_algebraMap_apply {r : Π i, R i} : + mapPiEvalRingHom I (algebraMap _ _ r) = algebraMap _ _ (r i) := + localRingHom_to_map .. -end RingHom +end AtPrime + +end Localization diff --git a/Mathlib/RingTheory/Localization/BaseChange.lean b/Mathlib/RingTheory/Localization/BaseChange.lean index 62ba26f974341..6099cbf7f523d 100644 --- a/Mathlib/RingTheory/Localization/BaseChange.lean +++ b/Mathlib/RingTheory/Localization/BaseChange.lean @@ -54,33 +54,46 @@ namespace IsLocalization include S open TensorProduct Algebra.TensorProduct -variable (M₁ M₂) [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R M₁] [Module R M₂] +variable (M₁ M₂ B C) [AddCommMonoid M₁] [AddCommMonoid M₂] [Module R M₁] [Module R M₂] [Module A M₁] [Module A M₂] [IsScalarTower R A M₁] [IsScalarTower R A M₂] + [Semiring B] [Algebra R B] [Algebra A B] [IsScalarTower R A B] + [Semiring C] [Algebra R C] [Algebra A C] [IsScalarTower R A C] theorem tensorProduct_compatibleSMul : CompatibleSMul R A M₁ M₂ where smul_tmul a _ _ := by - obtain ⟨r, s, rfl⟩ := IsLocalization.mk'_surjective S a + obtain ⟨r, s, rfl⟩ := mk'_surjective S a rw [← (map_units A s).smul_left_cancel] simp_rw [algebraMap_smul, smul_tmul', ← smul_assoc, smul_tmul, ← smul_assoc, smul_mk'_self, algebraMap_smul, smul_tmul] -noncomputable example : M₁ ⊗[A] M₂ ≃ₗ[A] M₁ ⊗[R] M₂ := +/-- If `A` is a localization of `R`, tensoring two `A`-modules over `A` is the same as +tensoring them over `R`. -/ +noncomputable def moduleTensorEquiv : M₁ ⊗[A] M₂ ≃ₗ[A] M₁ ⊗[R] M₂ := have := tensorProduct_compatibleSMul S A M₁ M₂ - equivOfCompatibleSMul R M₁ M₂ A + equivOfCompatibleSMul R A M₁ M₂ -noncomputable example : A ⊗[R] M₁ ≃ₗ[A] M₁ := +/-- If `A` is a localization of `R`, tensoring an `A`-module with `A` over `R` does nothing. -/ +noncomputable def moduleLid : A ⊗[R] M₁ ≃ₗ[A] M₁ := have := tensorProduct_compatibleSMul S A A M₁ - (equivOfCompatibleSMul R A M₁ A).symm ≪≫ₗ TensorProduct.lid _ _ + (equivOfCompatibleSMul R A A M₁).symm ≪≫ₗ TensorProduct.lid _ _ -/-- If A is a localization of a commutative ring R, the tensor product of A with A over R is -canonically isomorphic as A-algebras to A itself. -/ -noncomputable def tensorSelfAlgEquiv : A ⊗[R] A ≃ₐ[A] A := - have := tensorProduct_compatibleSMul S A A A - lmulEquiv R A +/-- If `A` is a localization of `R`, tensoring two `A`-algebras over `A` is the same as +tensoring them over `R`. -/ +noncomputable def algebraTensorEquiv : B ⊗[A] C ≃ₐ[A] B ⊗[R] C := + have := tensorProduct_compatibleSMul S A B C + Algebra.TensorProduct.equivOfCompatibleSMul R A B C + +/-- If `A` is a localization of `R`, tensoring an `A`-algebra with `A` over `R` does nothing. -/ +noncomputable def algebraLid : A ⊗[R] B ≃ₐ[A] B := + have := tensorProduct_compatibleSMul S A A B + Algebra.TensorProduct.lidOfCompatibleSMul R A B + +@[deprecated (since := "2024-12-01")] alias tensorSelfAlgEquiv := algebraLid set_option linter.docPrime false in theorem bijective_linearMap_mul' : Function.Bijective (LinearMap.mul' R A) := - (tensorSelfAlgEquiv S A).bijective + have := tensorProduct_compatibleSMul S A A A + (Algebra.TensorProduct.lmulEquiv R A).bijective end IsLocalization @@ -116,5 +129,5 @@ instance (R M : Type*) [CommRing R] [AddCommGroup M] [Module R M] suffices (if a = b then f m else 0) = e (1 ⊗ₜ[R] if a = b then m else 0) by simpa [e', Finsupp.single_apply, -EmbeddingLike.apply_eq_iff_eq, apply_ite e] split_ifs with h - swap; · simp - simp [e, IsBaseChange.equiv_tmul] + · simp [e, IsBaseChange.equiv_tmul] + · simp only [tmul_zero, LinearEquiv.trans_apply, LinearEquiv.restrictScalars_apply, map_zero] diff --git a/Mathlib/RingTheory/Localization/Basic.lean b/Mathlib/RingTheory/Localization/Basic.lean index 9159d55e9cdbd..6f9bf16ab95c9 100644 --- a/Mathlib/RingTheory/Localization/Basic.lean +++ b/Mathlib/RingTheory/Localization/Basic.lean @@ -7,7 +7,6 @@ import Mathlib.Algebra.Algebra.Tower import Mathlib.Algebra.Field.IsField import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.GroupTheory.MonoidLocalization.MonoidWithZero -import Mathlib.RingTheory.Ideal.Defs import Mathlib.RingTheory.Localization.Defs import Mathlib.RingTheory.OreLocalization.Ring @@ -68,9 +67,42 @@ localization, ring localization, commutative ring localization, characteristic p commutative ring, field of fractions -/ +assert_not_exists Ideal open Function +namespace Localization + +open IsLocalization + +variable {ι : Type*} {R : ι → Type*} [∀ i, CommSemiring (R i)] +variable {i : ι} (S : Submonoid (R i)) + +/-- `IsLocalization.map` applied to a projection homomorphism from a product ring. -/ +noncomputable abbrev mapPiEvalRingHom : + Localization (S.comap <| Pi.evalRingHom R i) →+* Localization S := + map (T := S) _ (Pi.evalRingHom R i) le_rfl + +open Function in +theorem mapPiEvalRingHom_bijective : Bijective (mapPiEvalRingHom S) := by + let T := S.comap (Pi.evalRingHom R i) + classical + refine ⟨fun x₁ x₂ eq ↦ ?_, fun x ↦ ?_⟩ + · obtain ⟨r₁, s₁, rfl⟩ := mk'_surjective T x₁ + obtain ⟨r₂, s₂, rfl⟩ := mk'_surjective T x₂ + simp_rw [map_mk'] at eq + rw [IsLocalization.eq] at eq ⊢ + obtain ⟨s, hs⟩ := eq + refine ⟨⟨update 0 i s, by apply update_same i s.1 0 ▸ s.2⟩, funext fun j ↦ ?_⟩ + obtain rfl | ne := eq_or_ne j i + · simpa using hs + · simp [update_noteq ne] + · obtain ⟨r, s, rfl⟩ := mk'_surjective S x + exact ⟨mk' (M := T) _ (update 0 i r) ⟨update 0 i s, by apply update_same i s.1 0 ▸ s.2⟩, + by simp [map_mk']⟩ + +end Localization + section CommSemiring variable {R : Type*} [CommSemiring R] {M N : Submonoid R} {S : Type*} [CommSemiring S] @@ -82,15 +114,6 @@ section IsLocalization variable [IsLocalization M S] -theorem mk'_mem_iff {x} {y : M} {I : Ideal S} : mk' S x y ∈ I ↔ algebraMap R S x ∈ I := by - constructor <;> intro h - · rw [← mk'_spec S x y, mul_comm] - exact I.mul_mem_left ((algebraMap R S) y) h - · rw [← mk'_spec S x y] at h - obtain ⟨b, hb⟩ := isUnit_iff_exists_inv.1 (map_units S y) - have := I.mul_mem_left b h - rwa [mul_comm, mul_assoc, hb, mul_one] at this - variable (M S) in include M in theorem linearMap_compatibleSMul (N₁ N₂) [AddCommMonoid N₁] [AddCommMonoid N₂] [Module R N₁] diff --git a/Mathlib/RingTheory/Localization/Defs.lean b/Mathlib/RingTheory/Localization/Defs.lean index 60509638366d3..afe729f268f40 100644 --- a/Mathlib/RingTheory/Localization/Defs.lean +++ b/Mathlib/RingTheory/Localization/Defs.lean @@ -8,6 +8,7 @@ import Mathlib.GroupTheory.MonoidLocalization.MonoidWithZero import Mathlib.RingTheory.OreLocalization.Ring import Mathlib.Tactic.ApplyFun import Mathlib.Tactic.Ring +import Mathlib.Algebra.BigOperators.Group.Finset /-! # Localizations of commutative rings diff --git a/Mathlib/RingTheory/Localization/FractionRing.lean b/Mathlib/RingTheory/Localization/FractionRing.lean index 155c5ec2966a3..309f147722deb 100644 --- a/Mathlib/RingTheory/Localization/FractionRing.lean +++ b/Mathlib/RingTheory/Localization/FractionRing.lean @@ -33,6 +33,7 @@ localization, ring localization, commutative ring localization, characteristic p commutative ring, field of fractions -/ +assert_not_exists Ideal variable (R : Type*) [CommRing R] {M : Submonoid R} (S : Type*) [CommRing S] variable [Algebra R S] {P : Type*} [CommRing P] @@ -222,6 +223,21 @@ such that `z = f x * (f y)⁻¹`. -/ noncomputable def lift (hg : Injective g) : K →+* L := IsLocalization.lift fun y : nonZeroDivisors A => isUnit_map_of_injective hg y +theorem lift_unique (hg : Function.Injective g) {f : K →+* L} + (hf1 : ∀ x, f (algebraMap A K x) = g x) : IsFractionRing.lift hg = f := + IsLocalization.lift_unique _ hf1 + +/-- Another version of unique to give two lift maps should be equal -/ +theorem ringHom_ext {f1 f2 : K →+* L} + (hf : ∀ x : A, f1 (algebraMap A K x) = f2 (algebraMap A K x)) : f1 = f2 := by + ext z + obtain ⟨x, y, hy, rfl⟩ := IsFractionRing.div_surjective (A := A) z + rw [map_div₀, map_div₀, hf, hf] + +theorem injective_comp_algebraMap : + Function.Injective fun (f : K →+* L) => f.comp (algebraMap A K) := + fun _ _ h => ringHom_ext (fun x => RingHom.congr_fun h x) + section liftAlgHom variable [Algebra R A] [Algebra R K] [IsScalarTower R A K] [Algebra R L] diff --git a/Mathlib/RingTheory/Localization/Ideal.lean b/Mathlib/RingTheory/Localization/Ideal.lean index 126d2cbf0c729..5e156755a12ed 100644 --- a/Mathlib/RingTheory/Localization/Ideal.lean +++ b/Mathlib/RingTheory/Localization/Ideal.lean @@ -5,7 +5,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan -/ import Mathlib.GroupTheory.MonoidLocalization.Away import Mathlib.RingTheory.Ideal.Quotient.Operations -import Mathlib.RingTheory.Localization.Basic +import Mathlib.RingTheory.Localization.Defs /-! # Ideals in localizations of commutative rings @@ -24,6 +24,16 @@ section CommSemiring variable {R : Type*} [CommSemiring R] (M : Submonoid R) (S : Type*) [CommSemiring S] variable [Algebra R S] [IsLocalization M S] +variable {M S} in +theorem mk'_mem_iff {x} {y : M} {I : Ideal S} : mk' S x y ∈ I ↔ algebraMap R S x ∈ I := by + constructor <;> intro h + · rw [← mk'_spec S x y, mul_comm] + exact I.mul_mem_left ((algebraMap R S) y) h + · rw [← mk'_spec S x y] at h + obtain ⟨b, hb⟩ := isUnit_iff_exists_inv.1 (map_units S y) + have := I.mul_mem_left b h + rwa [mul_comm, mul_assoc, hb, mul_one] at this + /-- Explicit characterization of the ideal given by `Ideal.map (algebraMap R S) I`. In practice, this ideal differs only in that the carrier set is defined explicitly. This definition is only meant to be used in proving `mem_map_algebraMap_iff`, @@ -37,7 +47,7 @@ private def map_ideal (I : Ideal R) : Ideal S where let Z : { x // x ∈ I } := ⟨(a'.2 : R) * (b'.1 : R) + (b'.2 : R) * (a'.1 : R), I.add_mem (I.mul_mem_left _ b'.1.2) (I.mul_mem_left _ a'.1.2)⟩ use ⟨Z, a'.2 * b'.2⟩ - simp only [RingHom.map_add, Submodule.coe_mk, Submonoid.coe_mul, RingHom.map_mul] + simp only [Z, RingHom.map_add, Submodule.coe_mk, Submonoid.coe_mul, RingHom.map_mul] rw [add_mul, ← mul_assoc a, ha, mul_comm (algebraMap R S a'.2) (algebraMap R S b'.2), ← mul_assoc b, hb] ring @@ -46,7 +56,7 @@ private def map_ideal (I : Ideal R) : Ideal S where obtain ⟨c', hc⟩ := IsLocalization.surj M c let Z : { x // x ∈ I } := ⟨c'.1 * x'.1, I.mul_mem_left c'.1 x'.1.2⟩ use ⟨Z, c'.2 * x'.2⟩ - simp only [← hx, ← hc, smul_eq_mul, Submodule.coe_mk, Submonoid.coe_mul, RingHom.map_mul] + simp only [Z, ← hx, ← hc, smul_eq_mul, Submodule.coe_mk, Submonoid.coe_mul, RingHom.map_mul] ring theorem mem_map_algebraMap_iff {I : Ideal R} {z} : z ∈ Ideal.map (algebraMap R S) I ↔ diff --git a/Mathlib/RingTheory/Localization/Integral.lean b/Mathlib/RingTheory/Localization/Integral.lean index ad327225f2383..cb310c7e3e585 100644 --- a/Mathlib/RingTheory/Localization/Integral.lean +++ b/Mathlib/RingTheory/Localization/Integral.lean @@ -6,7 +6,7 @@ Authors: Kenny Lau, Mario Carneiro, Johan Commelin, Amelia Livingston, Anne Baan import Mathlib.Algebra.GroupWithZero.NonZeroDivisors import Mathlib.Algebra.Polynomial.Lifts import Mathlib.GroupTheory.MonoidLocalization.Basic -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Integral import Mathlib.RingTheory.IntegralClosure.Algebra.Basic import Mathlib.RingTheory.Localization.FractionRing import Mathlib.RingTheory.Localization.Integer @@ -279,7 +279,7 @@ theorem IsIntegral.exists_multiple_integral_of_isLocalization [Algebra Rₘ S] [ end IsIntegral -variable {A K : Type*} [CommRing A] [IsDomain A] +variable {A K : Type*} [CommRing A] namespace IsIntegralClosure @@ -300,28 +300,25 @@ theorem isFractionRing_of_algebraic [Algebra.IsAlgebraic A L] mem_nonZeroDivisors_iff_ne_zero.mp hy ((injective_iff_map_eq_zero (algebraMap C L)).mp (algebraMap_injective C A L) _ h)) surj' := fun z => - let ⟨x, y, hy, hxy⟩ := exists_integral_multiple (Algebra.IsAlgebraic.isAlgebraic z) inj - ⟨⟨mk' C (x : L) x.2, algebraMap _ _ y, - mem_nonZeroDivisors_iff_ne_zero.mpr fun h => - hy (inj _ (by rw [IsScalarTower.algebraMap_apply A C L, h, RingHom.map_zero]))⟩, - by - simp only - rw [algebraMap_mk', ← IsScalarTower.algebraMap_apply A C L, hxy]⟩ + let ⟨x, hx, int⟩ := (Algebra.IsAlgebraic.isAlgebraic z).exists_integral_multiple + ((injective_iff_map_eq_zero _).mpr inj) + ⟨⟨mk' C _ int, algebraMap _ _ x, mem_nonZeroDivisors_of_ne_zero fun h ↦ + hx (inj _ <| by rw [IsScalarTower.algebraMap_apply A C L, h, RingHom.map_zero])⟩, by + rw [algebraMap_mk', ← IsScalarTower.algebraMap_apply A C L, Algebra.smul_def, mul_comm]⟩ exists_of_eq := fun {x y} h => ⟨1, by simpa using algebraMap_injective C A L h⟩ } variable (K L) /-- If the field `L` is a finite extension of the fraction field of the integral domain `A`, the integral closure `C` of `A` in `L` has fraction field `L`. -/ -theorem isFractionRing_of_finite_extension [Algebra K L] [IsScalarTower A K L] +theorem isFractionRing_of_finite_extension [IsDomain A] [Algebra K L] [IsScalarTower A K L] [FiniteDimensional K L] : IsFractionRing C L := have : Algebra.IsAlgebraic A L := IsFractionRing.comap_isAlgebraic_iff.mpr (inferInstanceAs (Algebra.IsAlgebraic K L)) isFractionRing_of_algebraic A C fun _ hx => IsFractionRing.to_map_eq_zero_iff.mp - ((_root_.map_eq_zero <| - algebraMap K L).mp <| (IsScalarTower.algebraMap_apply _ _ _ _).symm.trans hx) + ((map_eq_zero <| algebraMap K L).mp <| (IsScalarTower.algebraMap_apply _ _ _ _).symm.trans hx) end IsIntegralClosure @@ -341,8 +338,8 @@ variable (K L) /-- If the field `L` is a finite extension of the fraction field of the integral domain `A`, the integral closure of `A` in `L` has fraction field `L`. -/ -theorem isFractionRing_of_finite_extension [Algebra A L] [Algebra K L] [IsScalarTower A K L] - [FiniteDimensional K L] : IsFractionRing (integralClosure A L) L := +theorem isFractionRing_of_finite_extension [IsDomain A] [Algebra A L] [Algebra K L] + [IsScalarTower A K L] [FiniteDimensional K L] : IsFractionRing (integralClosure A L) L := IsIntegralClosure.isFractionRing_of_finite_extension A K L (integralClosure A L) end integralClosure diff --git a/Mathlib/RingTheory/MaximalSpectrum.lean b/Mathlib/RingTheory/MaximalSpectrum.lean index b9b3ccfdbd9db..9e400e2b5fb1c 100644 --- a/Mathlib/RingTheory/MaximalSpectrum.lean +++ b/Mathlib/RingTheory/MaximalSpectrum.lean @@ -3,7 +3,6 @@ Copyright (c) 2022 David Kurniadi Angdinata. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: David Kurniadi Angdinata -/ -import Mathlib.RingTheory.Ideal.Colon import Mathlib.RingTheory.Localization.AsSubring import Mathlib.RingTheory.PrimeSpectrum @@ -29,9 +28,7 @@ noncomputable section open scoped Classical -universe u v - -variable (R : Type u) [CommRing R] +variable (R S P : Type*) [CommSemiring R] [CommSemiring S] [CommSemiring P] /-- The maximal spectrum of a commutative ring `R` is the type of all maximal ideals of `R`. -/ @[ext] @@ -58,8 +55,8 @@ theorem toPrimeSpectrum_injective : (@toPrimeSpectrum R _).Injective := fun ⟨_ open PrimeSpectrum Set -variable (R) -variable [IsDomain R] (K : Type v) [Field K] [Algebra R K] [IsFractionRing R K] +variable (R : Type*) +variable [CommRing R] [IsDomain R] (K : Type*) [Field K] [Algebra R K] [IsFractionRing R K] /-- An integral domain is equal to the intersection of its localizations at all its maximal ideals viewed as subalgebras of its field of fractions. -/ @@ -70,23 +67,12 @@ theorem iInf_localization_eq_bot : (⨅ v : MaximalSpectrum R, constructor · contrapose intro hrange hlocal - let denom : Ideal R := (Submodule.span R {1} : Submodule R K).colon (Submodule.span R {x}) - have hdenom : (1 : R) ∉ denom := by - intro hdenom - rcases Submodule.mem_span_singleton.mp - (Submodule.mem_colon.mp hdenom x <| Submodule.mem_span_singleton_self x) with ⟨y, hy⟩ - exact hrange ⟨y, by rw [← mul_one <| algebraMap R K y, ← Algebra.smul_def, hy, one_smul]⟩ - rcases denom.exists_le_maximal fun h => (h ▸ hdenom) Submodule.mem_top with ⟨max, hmax, hle⟩ + let denom : Ideal R := (1 : Submodule R K).comap (LinearMap.toSpanSingleton R K x) + have hdenom : (1 : R) ∉ denom := by simpa [denom] using hrange + rcases denom.exists_le_maximal (denom.ne_top_iff_one.mpr hdenom) with ⟨max, hmax, hle⟩ rcases hlocal ⟨max, hmax⟩ with ⟨n, d, hd, rfl⟩ - apply hd (hle <| Submodule.mem_colon.mpr fun _ hy => _) - intro _ hy - rcases Submodule.mem_span_singleton.mp hy with ⟨y, rfl⟩ - exact Submodule.mem_span_singleton.mpr ⟨y * n, by - rw [Algebra.smul_def, mul_one, map_mul, smul_comm, Algebra.smul_def, Algebra.smul_def, - mul_comm <| algebraMap R K d, - inv_mul_cancel_right₀ <| - (map_ne_zero_iff _ <| NoZeroSMulDivisors.algebraMap_injective R K).mpr fun h => - (h ▸ hd) max.zero_mem]⟩ + exact hd (hle ⟨n, by simp [denom, Algebra.smul_def, mul_left_comm, mul_inv_cancel₀ <| + (map_ne_zero_iff _ <| IsFractionRing.injective R K).mpr fun h ↦ hd (h ▸ max.zero_mem :)]⟩) · rintro ⟨y, rfl⟩ ⟨v, hv⟩ exact ⟨y, 1, v.ne_top_iff_one.mp hv.ne_top, by rw [map_one, inv_one, mul_one]⟩ @@ -94,20 +80,222 @@ end MaximalSpectrum namespace PrimeSpectrum -variable (R) -variable [IsDomain R] (K : Type v) [Field K] [Algebra R K] [IsFractionRing R K] +variable (R : Type*) +variable [CommRing R] [IsDomain R] (K : Type*) [Field K] [Algebra R K] [IsFractionRing R K] /-- An integral domain is equal to the intersection of its localizations at all its prime ideals viewed as subalgebras of its field of fractions. -/ theorem iInf_localization_eq_bot : ⨅ v : PrimeSpectrum R, Localization.subalgebra.ofField K _ (v.asIdeal.primeCompl_le_nonZeroDivisors) = ⊥ := by - ext x - rw [Algebra.mem_iInf] - constructor - · rw [← MaximalSpectrum.iInf_localization_eq_bot, Algebra.mem_iInf] - exact fun hx ⟨v, hv⟩ => hx ⟨v, hv.isPrime⟩ - · rw [Algebra.mem_bot] - rintro ⟨y, rfl⟩ ⟨v, hv⟩ - exact ⟨y, 1, v.ne_top_iff_one.mp hv.ne_top, by rw [map_one, inv_one, mul_one]⟩ + refine bot_unique (.trans (fun _ ↦ ?_) (MaximalSpectrum.iInf_localization_eq_bot R K).le) + simpa only [Algebra.mem_iInf] using fun hx ⟨v, hv⟩ ↦ hx ⟨v, hv.isPrime⟩ + +end PrimeSpectrum + +namespace MaximalSpectrum + +variable (R) + +/-- The product of localizations at all maximal ideals of a commutative semiring. -/ +abbrev PiLocalization : Type _ := Π I : MaximalSpectrum R, Localization.AtPrime I.1 + +/-- The canonical ring homomorphism from a commutative semiring to the product of its +localizations at all maximal ideals. It is always injective. -/ +def toPiLocalization : R →+* PiLocalization R := algebraMap R _ + +theorem toPiLocalization_injective : Function.Injective (toPiLocalization R) := fun r r' eq ↦ by + rw [← one_mul r, ← one_mul r'] + by_contra ne + have ⟨I, mI, hI⟩ := (Module.eqIdeal R r r').exists_le_maximal ((Ideal.ne_top_iff_one _).mpr ne) + have ⟨s, hs⟩ := (IsLocalization.eq_iff_exists I.primeCompl _).mp (congr_fun eq ⟨I, mI⟩) + exact s.2 (hI hs) + +theorem toPiLocalization_apply_apply {r I} : toPiLocalization R r I = algebraMap R _ r := rfl + +variable {R S} (f : R →+* S) (g : S →+* P) (hf : Function.Bijective f) (hg : Function.Bijective g) + +/-- Functoriality of `PiLocalization` but restricted to bijective ring homs. +If R and S are commutative rings, surjectivity would be enough. -/ +noncomputable def mapPiLocalization : PiLocalization R →+* PiLocalization S := + Pi.ringHom fun I ↦ (Localization.localRingHom _ _ f rfl).comp <| + Pi.evalRingHom _ (⟨_, I.2.comap_bijective f hf⟩ : MaximalSpectrum R) + +theorem mapPiLocalization_naturality : + (mapPiLocalization f hf).comp (toPiLocalization R) = + (toPiLocalization S).comp f := by + ext r I + show Localization.localRingHom _ _ _ rfl (algebraMap _ _ r) = algebraMap _ _ (f r) + simp_rw [← IsLocalization.mk'_one (M := (I.1.comap f).primeCompl), Localization.localRingHom_mk', + ← IsLocalization.mk'_one (M := I.1.primeCompl), Submonoid.coe_one, map_one f] + rfl + +theorem mapPiLocalization_id : mapPiLocalization (.id R) Function.bijective_id = .id _ := + RingHom.ext fun _ ↦ funext fun _ ↦ congr($(Localization.localRingHom_id _) _) + +theorem mapPiLocalization_comp : + mapPiLocalization (g.comp f) (hg.comp hf) = + (mapPiLocalization g hg).comp (mapPiLocalization f hf) := + RingHom.ext fun _ ↦ funext fun _ ↦ congr($(Localization.localRingHom_comp _ _ _ _ rfl _ rfl) _) + +theorem mapPiLocalization_bijective : Function.Bijective (mapPiLocalization f hf) := by + let f := RingEquiv.ofBijective f hf + let e := RingEquiv.ofRingHom (mapPiLocalization f hf) + (mapPiLocalization (f.symm : S →+* R) f.symm.bijective) ?_ ?_ + · exact e.bijective + · rw [← mapPiLocalization_comp] + simp_rw [RingEquiv.comp_symm, mapPiLocalization_id] + · rw [← mapPiLocalization_comp] + simp_rw [RingEquiv.symm_comp, mapPiLocalization_id] + +section Pi + +variable {ι} (R : ι → Type*) [∀ i, CommSemiring (R i)] [∀ i, Nontrivial (R i)] + +theorem toPiLocalization_not_surjective_of_infinite [Infinite ι] : + ¬ Function.Surjective (toPiLocalization (Π i, R i)) := fun surj ↦ by + have ⟨J, max, nmem⟩ := PrimeSpectrum.exists_maximal_nmem_range_sigmaToPi_of_infinite R + obtain ⟨r, hr⟩ := surj (Function.update 0 ⟨J, max⟩ 1) + have : r = 0 := funext fun i ↦ toPiLocalization_injective _ <| funext fun I ↦ by + replace hr := congr_fun hr ⟨_, I.2.comap_piEvalRingHom⟩ + dsimp only [toPiLocalization_apply_apply, Subtype.coe_mk] at hr + simp_rw [toPiLocalization_apply_apply, + ← Localization.AtPrime.mapPiEvalRingHom_algebraMap_apply, hr] + rw [Function.update_noteq]; · simp_rw [Pi.zero_apply, map_zero] + exact fun h ↦ nmem ⟨⟨i, I.1, I.2.isPrime⟩, PrimeSpectrum.ext congr($h.1)⟩ + replace hr := congr_fun hr ⟨J, max⟩ + rw [this, map_zero, Function.update_same] at hr + exact zero_ne_one hr + +variable {R} + +theorem finite_of_toPiLocalization_pi_surjective + (h : Function.Surjective (toPiLocalization (Π i, R i))) : + Finite ι := by + contrapose h; rw [not_finite_iff_infinite] at h + exact toPiLocalization_not_surjective_of_infinite _ + +end Pi + +theorem finite_of_toPiLocalization_surjective + (surj : Function.Surjective (toPiLocalization R)) : + Finite (MaximalSpectrum R) := by + replace surj := mapPiLocalization_bijective _ ⟨toPiLocalization_injective R, surj⟩ + |>.2.comp surj + rw [← RingHom.coe_comp, mapPiLocalization_naturality, RingHom.coe_comp] at surj + exact finite_of_toPiLocalization_pi_surjective surj.of_comp + +end MaximalSpectrum + +namespace PrimeSpectrum + +variable (R) + +/-- The product of localizations at all prime ideals of a commutative semiring. -/ +abbrev PiLocalization : Type _ := Π p : PrimeSpectrum R, Localization p.asIdeal.primeCompl + +/-- The canonical ring homomorphism from a commutative semiring to the product of its +localizations at all prime ideals. It is always injective. -/ +def toPiLocalization : R →+* PiLocalization R := algebraMap R _ + +theorem toPiLocalization_injective : Function.Injective (toPiLocalization R) := + fun _ _ eq ↦ MaximalSpectrum.toPiLocalization_injective R <| + funext fun I ↦ congr_fun eq I.toPrimeSpectrum + +/-- The projection from the product of localizations at primes to the product of +localizations at maximal ideals. -/ +def piLocalizationToMaximal : PiLocalization R →+* MaximalSpectrum.PiLocalization R := + Pi.ringHom fun I ↦ Pi.evalRingHom _ I.toPrimeSpectrum + +theorem piLocalizationToMaximal_surjective : Function.Surjective (piLocalizationToMaximal R) := + fun r ↦ ⟨fun I ↦ if h : I.1.IsMaximal then r ⟨_, h⟩ else 0, funext fun _ ↦ dif_pos _⟩ + +variable {R} + +/-- If R has Krull dimension ≤ 0, then `piLocalizationToIsMaximal R` is an isomorphism. -/ +def piLocalizationToMaximalEquiv (h : ∀ I : Ideal R, I.IsPrime → I.IsMaximal) : + PiLocalization R ≃+* MaximalSpectrum.PiLocalization R where + __ := piLocalizationToMaximal R + invFun := Pi.ringHom fun I ↦ Pi.evalRingHom _ (⟨_, h _ I.2⟩ : MaximalSpectrum R) + left_inv _ := rfl + right_inv _ := rfl + +theorem piLocalizationToMaximal_bijective (h : ∀ I : Ideal R, I.IsPrime → I.IsMaximal) : + Function.Bijective (piLocalizationToMaximal R) := + (piLocalizationToMaximalEquiv h).bijective + +theorem piLocalizationToMaximal_comp_toPiLocalization : + (piLocalizationToMaximal R).comp (toPiLocalization R) = MaximalSpectrum.toPiLocalization R := + rfl + +variable {S} + +theorem isMaximal_of_toPiLocalization_surjective (surj : Function.Surjective (toPiLocalization R)) + (I : PrimeSpectrum R) : I.1.IsMaximal := by + have ⟨J, max, le⟩ := I.1.exists_le_maximal I.2.ne_top + obtain ⟨r, hr⟩ := surj (Function.update 0 ⟨J, max.isPrime⟩ 1) + by_contra h + have hJ : algebraMap _ _ r = _ := (congr_fun hr _).trans (Function.update_same _ _ _) + have hI : algebraMap _ _ r = _ := congr_fun hr I + rw [← IsLocalization.lift_eq (M := J.primeCompl) (S := Localization J.primeCompl), hJ, map_one, + Function.update_noteq] at hI + · exact one_ne_zero hI + · intro eq; have : I.1 = J := congr_arg (·.1) eq; exact h (this ▸ max) + · exact fun ⟨s, hs⟩ ↦ IsLocalization.map_units (M := I.1.primeCompl) _ ⟨s, fun h ↦ hs (le h)⟩ + +variable (f : R →+* S) + +/-- A ring homomorphism induces a homomorphism between the products of localizations at primes. -/ +noncomputable def mapPiLocalization : PiLocalization R →+* PiLocalization S := + Pi.ringHom fun I ↦ (Localization.localRingHom _ I.1 f rfl).comp (Pi.evalRingHom _ (f.specComap I)) + +theorem mapPiLocalization_naturality : + (mapPiLocalization f).comp (toPiLocalization R) = (toPiLocalization S).comp f := by + ext r I + show Localization.localRingHom _ _ _ rfl (algebraMap _ _ r) = algebraMap _ _ (f r) + simp_rw [← IsLocalization.mk'_one (M := (I.1.comap f).primeCompl), Localization.localRingHom_mk', + ← IsLocalization.mk'_one (M := I.1.primeCompl), Submonoid.coe_one, map_one f] + rfl + +theorem mapPiLocalization_id : mapPiLocalization (.id R) = .id _ := by + ext; exact congr($(Localization.localRingHom_id _) _) + +theorem mapPiLocalization_comp (g : S →+* P) : + mapPiLocalization (g.comp f) = (mapPiLocalization g).comp (mapPiLocalization f) := by + ext; exact congr($(Localization.localRingHom_comp _ _ _ _ rfl _ rfl) _) + +theorem mapPiLocalization_bijective (hf : Function.Bijective f) : + Function.Bijective (mapPiLocalization f) := by + let f := RingEquiv.ofBijective f hf + let e := RingEquiv.ofRingHom (mapPiLocalization (f : R →+* S)) (mapPiLocalization f.symm) ?_ ?_ + · exact e.bijective + · rw [← mapPiLocalization_comp, RingEquiv.comp_symm, mapPiLocalization_id] + · rw [← mapPiLocalization_comp, RingEquiv.symm_comp, mapPiLocalization_id] + +section Pi + +variable {ι} (R : ι → Type*) [∀ i, CommSemiring (R i)] [∀ i, Nontrivial (R i)] + +theorem toPiLocalization_not_surjective_of_infinite [Infinite ι] : + ¬ Function.Surjective (toPiLocalization (Π i, R i)) := + fun surj ↦ MaximalSpectrum.toPiLocalization_not_surjective_of_infinite R <| by + rw [← piLocalizationToMaximal_comp_toPiLocalization] + exact (piLocalizationToMaximal_surjective _).comp surj + +variable {R} + +theorem finite_of_toPiLocalization_pi_surjective + (h : Function.Surjective (toPiLocalization (Π i, R i))) : + Finite ι := by + contrapose h; rw [not_finite_iff_infinite] at h + exact toPiLocalization_not_surjective_of_infinite _ + +end Pi + +theorem finite_of_toPiLocalization_surjective + (surj : Function.Surjective (toPiLocalization R)) : + Finite (PrimeSpectrum R) := by + replace surj := (mapPiLocalization_bijective _ ⟨toPiLocalization_injective R, surj⟩).2.comp surj + rw [← RingHom.coe_comp, mapPiLocalization_naturality, RingHom.coe_comp] at surj + exact finite_of_toPiLocalization_pi_surjective surj.of_comp end PrimeSpectrum diff --git a/Mathlib/RingTheory/Multiplicity.lean b/Mathlib/RingTheory/Multiplicity.lean index c095227abd535..19c092dd8f1ed 100644 --- a/Mathlib/RingTheory/Multiplicity.lean +++ b/Mathlib/RingTheory/Multiplicity.lean @@ -6,8 +6,8 @@ Authors: Robert Y. Lewis, Chris Hughes, Daniel Weber import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.Finset import Mathlib.Algebra.Ring.Divisibility.Basic +import Mathlib.Algebra.Ring.Int.Defs import Mathlib.Data.ENat.Basic -import Mathlib.Tactic.Linarith /-! # Multiplicity of a divisor @@ -22,7 +22,7 @@ several basic results on it. `n`. * `multiplicity a b`: a `ℕ`-valued version of `multiplicity`, defaulting for `1` instead of `⊤`. The reason for using `1` as a default value instead of `0` is to have `multiplicity_eq_zero_iff`. -* `multiplicity.Finite a b`: a predicate denoting that the multiplicity of `a` in `b` is finite. +* `FiniteMultiplicity a b`: a predicate denoting that the multiplicity of `a` in `b` is finite. -/ @@ -31,47 +31,56 @@ variable {α β : Type*} open Nat /-- `multiplicity.Finite a b` indicates that the multiplicity of `a` in `b` is finite. -/ -abbrev multiplicity.Finite [Monoid α] (a b : α) : Prop := +abbrev FiniteMultiplicity [Monoid α] (a b : α) : Prop := ∃ n : ℕ, ¬a ^ (n + 1) ∣ b +@[deprecated (since := "2024-11-30")] alias multiplicity.Finite := FiniteMultiplicity + open scoped Classical in /-- `emultiplicity a b` returns the largest natural number `n` such that `a ^ n ∣ b`, as an `ℕ∞`. If `∀ n, a ^ n ∣ b` then it returns `⊤`. -/ noncomputable def emultiplicity [Monoid α] (a b : α) : ℕ∞ := - if h : multiplicity.Finite a b then Nat.find h else ⊤ + if h : FiniteMultiplicity a b then Nat.find h else ⊤ /-- A `ℕ`-valued version of `emultiplicity`, returning `1` instead of `⊤`. -/ noncomputable def multiplicity [Monoid α] (a b : α) : ℕ := (emultiplicity a b).untop' 1 -open multiplicity - section Monoid variable [Monoid α] [Monoid β] {a b : α} @[simp] theorem emultiplicity_eq_top : - emultiplicity a b = ⊤ ↔ ¬Finite a b := by + emultiplicity a b = ⊤ ↔ ¬FiniteMultiplicity a b := by simp [emultiplicity] -theorem emultiplicity_lt_top {a b : α} : emultiplicity a b < ⊤ ↔ Finite a b := by +theorem emultiplicity_lt_top {a b : α} : emultiplicity a b < ⊤ ↔ FiniteMultiplicity a b := by simp [lt_top_iff_ne_top, emultiplicity_eq_top] -theorem finite_iff_emultiplicity_ne_top : - Finite a b ↔ emultiplicity a b ≠ ⊤ := by simp +theorem finiteMultiplicity_iff_emultiplicity_ne_top : + FiniteMultiplicity a b ↔ emultiplicity a b ≠ ⊤ := by simp + +@[deprecated (since := "2024-11-30")] +alias finite_iff_emultiplicity_ne_top := finiteMultiplicity_iff_emultiplicity_ne_top -alias ⟨multiplicity.Finite.emultiplicity_ne_top, _⟩ := finite_iff_emultiplicity_ne_top +alias ⟨FiniteMultiplicity.emultiplicity_ne_top, _⟩ := finite_iff_emultiplicity_ne_top + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_ne_top := FiniteMultiplicity.emultiplicity_ne_top @[deprecated (since := "2024-11-08")] -alias Finite.emultiplicity_ne_top := multiplicity.Finite.emultiplicity_ne_top +alias Finite.emultiplicity_ne_top := FiniteMultiplicity.emultiplicity_ne_top -theorem finite_of_emultiplicity_eq_natCast {n : ℕ} (h : emultiplicity a b = n) : - Finite a b := by +theorem finiteMultiplicity_of_emultiplicity_eq_natCast {n : ℕ} (h : emultiplicity a b = n) : + FiniteMultiplicity a b := by by_contra! nh rw [← emultiplicity_eq_top, h] at nh trivial +@[deprecated (since := "2024-11-30")] +alias finite_of_emultiplicity_eq_natCast := finiteMultiplicity_of_emultiplicity_eq_natCast + theorem multiplicity_eq_of_emultiplicity_eq_some {n : ℕ} (h : emultiplicity a b = n) : multiplicity a b = n := by simp [multiplicity, h] @@ -81,16 +90,24 @@ theorem emultiplicity_ne_of_multiplicity_ne {n : ℕ} : multiplicity a b ≠ n → emultiplicity a b ≠ n := mt multiplicity_eq_of_emultiplicity_eq_some -theorem multiplicity.Finite.emultiplicity_eq_multiplicity (h : Finite a b) : +theorem FiniteMultiplicity.emultiplicity_eq_multiplicity (h : FiniteMultiplicity a b) : emultiplicity a b = multiplicity a b := by cases hm : emultiplicity a b · simp [h] at hm rw [multiplicity_eq_of_emultiplicity_eq_some hm] -theorem multiplicity.Finite.emultiplicity_eq_iff_multiplicity_eq {n : ℕ} (h : Finite a b) : - emultiplicity a b = n ↔ multiplicity a b = n := by +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_eq_multiplicity := + FiniteMultiplicity.emultiplicity_eq_multiplicity + +theorem FiniteMultiplicity.emultiplicity_eq_iff_multiplicity_eq {n : ℕ} + (h : FiniteMultiplicity a b) : emultiplicity a b = n ↔ multiplicity a b = n := by simp [h.emultiplicity_eq_multiplicity] +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_eq_iff_multiplicity_eq := + FiniteMultiplicity.emultiplicity_eq_iff_multiplicity_eq + theorem emultiplicity_eq_iff_multiplicity_eq_of_ne_one {n : ℕ} (h : n ≠ 1) : emultiplicity a b = n ↔ multiplicity a b = n := by constructor @@ -103,14 +120,18 @@ theorem emultiplicity_eq_zero_iff_multiplicity_eq_zero : emultiplicity_eq_iff_multiplicity_eq_of_ne_one zero_ne_one @[simp] -theorem multiplicity_eq_one_of_not_finite (h : ¬Finite a b) : +theorem multiplicity_eq_one_of_not_finiteMultiplicity (h : ¬FiniteMultiplicity a b) : multiplicity a b = 1 := by simp [multiplicity, emultiplicity_eq_top.2 h] +@[deprecated (since := "2024-11-30")] +alias multiplicity_eq_one_of_not_finite := + multiplicity_eq_one_of_not_finiteMultiplicity + @[simp] theorem multiplicity_le_emultiplicity : multiplicity a b ≤ emultiplicity a b := by - by_cases hf : Finite a b + by_cases hf : FiniteMultiplicity a b · simp [hf.emultiplicity_eq_multiplicity] · simp [hf, emultiplicity_eq_top.2] @@ -124,52 +145,73 @@ theorem multiplicity_le_of_emultiplicity_le {n : ℕ} (h : emultiplicity a b ≤ multiplicity a b ≤ n := by exact_mod_cast multiplicity_le_emultiplicity.trans h -theorem multiplicity.Finite.emultiplicity_le_of_multiplicity_le (hfin : Finite a b) +theorem FiniteMultiplicity.emultiplicity_le_of_multiplicity_le (hfin : FiniteMultiplicity a b) {n : ℕ} (h : multiplicity a b ≤ n) : emultiplicity a b ≤ n := by rw [emultiplicity_eq_multiplicity hfin] assumption_mod_cast +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_le_of_multiplicity_le := + FiniteMultiplicity.emultiplicity_le_of_multiplicity_le + theorem le_emultiplicity_of_le_multiplicity {n : ℕ} (h : n ≤ multiplicity a b) : n ≤ emultiplicity a b := by exact_mod_cast (WithTop.coe_mono h).trans multiplicity_le_emultiplicity -theorem multiplicity.Finite.le_multiplicity_of_le_emultiplicity (hfin : Finite a b) +theorem FiniteMultiplicity.le_multiplicity_of_le_emultiplicity (hfin : FiniteMultiplicity a b) {n : ℕ} (h : n ≤ emultiplicity a b) : n ≤ multiplicity a b := by rw [emultiplicity_eq_multiplicity hfin] at h assumption_mod_cast +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.le_multiplicity_of_le_emultiplicity := + FiniteMultiplicity.le_multiplicity_of_le_emultiplicity + theorem multiplicity_lt_of_emultiplicity_lt {n : ℕ} (h : emultiplicity a b < n) : multiplicity a b < n := by exact_mod_cast multiplicity_le_emultiplicity.trans_lt h -theorem multiplicity.Finite.emultiplicity_lt_of_multiplicity_lt (hfin : Finite a b) +theorem FiniteMultiplicity.emultiplicity_lt_of_multiplicity_lt (hfin : FiniteMultiplicity a b) {n : ℕ} (h : multiplicity a b < n) : emultiplicity a b < n := by rw [emultiplicity_eq_multiplicity hfin] assumption_mod_cast +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_lt_of_multiplicity_lt := + FiniteMultiplicity.emultiplicity_lt_of_multiplicity_lt + theorem lt_emultiplicity_of_lt_multiplicity {n : ℕ} (h : n < multiplicity a b) : n < emultiplicity a b := by exact_mod_cast (WithTop.coe_strictMono h).trans_le multiplicity_le_emultiplicity -theorem multiplicity.Finite.lt_multiplicity_of_lt_emultiplicity (hfin : Finite a b) +theorem FiniteMultiplicity.lt_multiplicity_of_lt_emultiplicity (hfin : FiniteMultiplicity a b) {n : ℕ} (h : n < emultiplicity a b) : n < multiplicity a b := by rw [emultiplicity_eq_multiplicity hfin] at h assumption_mod_cast +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.lt_multiplicity_of_lt_emultiplicity := + FiniteMultiplicity.lt_multiplicity_of_lt_emultiplicity + theorem emultiplicity_pos_iff : 0 < emultiplicity a b ↔ 0 < multiplicity a b := by simp [pos_iff_ne_zero, pos_iff_ne_zero, emultiplicity_eq_zero_iff_multiplicity_eq_zero] -theorem multiplicity.Finite.def : Finite a b ↔ ∃ n : ℕ, ¬a ^ (n + 1) ∣ b := +theorem FiniteMultiplicity.def : FiniteMultiplicity a b ↔ ∃ n : ℕ, ¬a ^ (n + 1) ∣ b := Iff.rfl -theorem multiplicity.Finite.not_dvd_of_one_right : Finite a 1 → ¬a ∣ 1 := fun ⟨n, hn⟩ ⟨d, hd⟩ => - hn ⟨d ^ (n + 1), (pow_mul_pow_eq_one (n + 1) hd.symm).symm⟩ +@[deprecated (since := "2024-11-30")] alias multiplicity.Finite.def := FiniteMultiplicity.def + +theorem FiniteMultiplicity.not_dvd_of_one_right : FiniteMultiplicity a 1 → ¬a ∣ 1 := + fun ⟨n, hn⟩ ⟨d, hd⟩ => hn ⟨d ^ (n + 1), (pow_mul_pow_eq_one (n + 1) hd.symm).symm⟩ + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_dvd_of_one_right := FiniteMultiplicity.not_dvd_of_one_right @[norm_cast] theorem Int.natCast_emultiplicity (a b : ℕ) : emultiplicity (a : ℤ) (b : ℤ) = emultiplicity a b := by - unfold emultiplicity multiplicity.Finite + unfold emultiplicity FiniteMultiplicity congr! <;> norm_cast @[norm_cast] @@ -178,22 +220,32 @@ theorem Int.natCast_multiplicity (a b : ℕ) : multiplicity (a : ℤ) (b : ℤ) @[deprecated (since := "2024-04-05")] alias Int.coe_nat_multiplicity := Int.natCast_multiplicity -theorem multiplicity.Finite.not_iff_forall : ¬Finite a b ↔ ∀ n : ℕ, a ^ n ∣ b := +theorem FiniteMultiplicity.not_iff_forall : ¬FiniteMultiplicity a b ↔ ∀ n : ℕ, a ^ n ∣ b := ⟨fun h n => Nat.casesOn n (by rw [_root_.pow_zero] exact one_dvd _) - (by simpa [multiplicity.Finite, Classical.not_not] using h), - by simp [multiplicity.Finite, multiplicity, Classical.not_not]; tauto⟩ + (by simpa [FiniteMultiplicity] using h), + by simp [FiniteMultiplicity, multiplicity]; tauto⟩ -theorem multiplicity.Finite.not_unit (h : Finite a b) : ¬IsUnit a := +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_iff_forall := FiniteMultiplicity.not_iff_forall + +theorem FiniteMultiplicity.not_unit (h : FiniteMultiplicity a b) : ¬IsUnit a := let ⟨n, hn⟩ := h hn ∘ IsUnit.dvd ∘ IsUnit.pow (n + 1) -theorem multiplicity.Finite.mul_left {c : α} : Finite a (b * c) → Finite a b := fun ⟨n, hn⟩ => +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_unit := FiniteMultiplicity.not_unit + +theorem FiniteMultiplicity.mul_left {c : α} : + FiniteMultiplicity a (b * c) → FiniteMultiplicity a b := fun ⟨n, hn⟩ => ⟨n, fun h => hn (h.trans (dvd_mul_right _ _))⟩ +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.mul_left := FiniteMultiplicity.mul_left + theorem pow_dvd_of_le_emultiplicity {k : ℕ} (hk : k ≤ emultiplicity a b) : a ^ k ∣ b := by classical cases k @@ -202,7 +254,7 @@ theorem pow_dvd_of_le_emultiplicity {k : ℕ} (hk : k ≤ emultiplicity a b) : split at hk · norm_cast at hk simpa using (Nat.find_min _ (lt_of_succ_le hk)) - · apply Finite.not_iff_forall.mp ‹_› + · apply FiniteMultiplicity.not_iff_forall.mp ‹_› theorem pow_dvd_of_le_multiplicity {k : ℕ} (hk : k ≤ multiplicity a b) : a ^ k ∣ b := pow_dvd_of_le_emultiplicity (le_emultiplicity_of_le_multiplicity hk) @@ -220,15 +272,19 @@ theorem not_pow_dvd_of_emultiplicity_lt {m : ℕ} (hm : emultiplicity a b < m) : exact hn2 ((pow_dvd_pow _ hn1).trans nh) · simp at hm -theorem multiplicity.Finite.not_pow_dvd_of_multiplicity_lt (hf : Finite a b) {m : ℕ} +theorem FiniteMultiplicity.not_pow_dvd_of_multiplicity_lt (hf : FiniteMultiplicity a b) {m : ℕ} (hm : multiplicity a b < m) : ¬a ^ m ∣ b := by apply not_pow_dvd_of_emultiplicity_lt rw [hf.emultiplicity_eq_multiplicity] norm_cast +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_pow_dvd_of_multiplicity_lt := + FiniteMultiplicity.not_pow_dvd_of_multiplicity_lt + theorem multiplicity_pos_of_dvd (hdiv : a ∣ b) : 0 < multiplicity a b := by refine zero_lt_iff.2 fun h => ?_ - simpa [hdiv] using Finite.not_pow_dvd_of_multiplicity_lt + simpa [hdiv] using FiniteMultiplicity.not_pow_dvd_of_multiplicity_lt (by by_contra! nh; simp [nh] at h) (lt_one_iff.mpr h) theorem emultiplicity_pos_of_dvd (hdiv : a ∣ b) : 0 < emultiplicity a b := @@ -236,7 +292,7 @@ theorem emultiplicity_pos_of_dvd (hdiv : a ∣ b) : 0 < emultiplicity a b := theorem emultiplicity_eq_of_dvd_of_not_dvd {k : ℕ} (hk : a ^ k ∣ b) (hsucc : ¬a ^ (k + 1) ∣ b) : emultiplicity a b = k := by classical - have : Finite a b := ⟨k, hsucc⟩ + have : FiniteMultiplicity a b := ⟨k, hsucc⟩ simp only [emultiplicity, this, ↓reduceDIte, Nat.cast_inj, find_eq_iff, hsucc, not_false_eq_true, Decidable.not_not, true_and] exact fun n hn ↦ (pow_dvd_pow _ hn).trans hk @@ -249,24 +305,36 @@ theorem le_emultiplicity_of_pow_dvd {k : ℕ} (hk : a ^ k ∣ b) : k ≤ emultiplicity a b := le_of_not_gt fun hk' => not_pow_dvd_of_emultiplicity_lt hk' hk -theorem multiplicity.Finite.le_multiplicity_of_pow_dvd (hf : Finite a b) {k : ℕ} (hk : a ^ k ∣ b) : - k ≤ multiplicity a b := +theorem FiniteMultiplicity.le_multiplicity_of_pow_dvd (hf : FiniteMultiplicity a b) + {k : ℕ} (hk : a ^ k ∣ b) : k ≤ multiplicity a b := hf.le_multiplicity_of_le_emultiplicity (le_emultiplicity_of_pow_dvd hk) +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.le_multiplicity_of_pow_dvd := + FiniteMultiplicity.le_multiplicity_of_pow_dvd + theorem pow_dvd_iff_le_emultiplicity {k : ℕ} : a ^ k ∣ b ↔ k ≤ emultiplicity a b := ⟨le_emultiplicity_of_pow_dvd, pow_dvd_of_le_emultiplicity⟩ -theorem multiplicity.Finite.pow_dvd_iff_le_multiplicity (hf : Finite a b) {k : ℕ} : +theorem FiniteMultiplicity.pow_dvd_iff_le_multiplicity (hf : FiniteMultiplicity a b) {k : ℕ} : a ^ k ∣ b ↔ k ≤ multiplicity a b := by exact_mod_cast hf.emultiplicity_eq_multiplicity ▸ pow_dvd_iff_le_emultiplicity +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.pow_dvd_iff_le_multiplicity := + FiniteMultiplicity.pow_dvd_iff_le_multiplicity + theorem emultiplicity_lt_iff_not_dvd {k : ℕ} : emultiplicity a b < k ↔ ¬a ^ k ∣ b := by rw [pow_dvd_iff_le_emultiplicity, not_le] -theorem multiplicity.Finite.multiplicity_lt_iff_not_dvd {k : ℕ} (hf : Finite a b) : +theorem FiniteMultiplicity.multiplicity_lt_iff_not_dvd {k : ℕ} (hf : FiniteMultiplicity a b) : multiplicity a b < k ↔ ¬a ^ k ∣ b := by rw [hf.pow_dvd_iff_le_multiplicity, not_le] +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.multiplicity_lt_iff_not_dvd := + FiniteMultiplicity.multiplicity_lt_iff_not_dvd + theorem emultiplicity_eq_coe {n : ℕ} : emultiplicity a b = n ↔ a ^ n ∣ b ∧ ¬a ^ (n + 1) ∣ b := by constructor @@ -281,33 +349,48 @@ theorem emultiplicity_eq_coe {n : ℕ} : · rw [and_imp] apply emultiplicity_eq_of_dvd_of_not_dvd -theorem multiplicity.Finite.multiplicity_eq_iff (hf : Finite a b) {n : ℕ} : +theorem FiniteMultiplicity.multiplicity_eq_iff (hf : FiniteMultiplicity a b) {n : ℕ} : multiplicity a b = n ↔ a ^ n ∣ b ∧ ¬a ^ (n + 1) ∣ b := by simp [← emultiplicity_eq_coe, hf.emultiplicity_eq_multiplicity] +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.multiplicity_eq_iff := FiniteMultiplicity.multiplicity_eq_iff + @[simp] -theorem multiplicity.Finite.not_of_isUnit_left (b : α) (ha : IsUnit a) : ¬Finite a b := +theorem FiniteMultiplicity.not_of_isUnit_left (b : α) (ha : IsUnit a) : ¬FiniteMultiplicity a b := (·.not_unit ha) -theorem multiplicity.Finite.not_of_one_left (b : α) : ¬ Finite 1 b := by simp +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_of_isUnit_left := FiniteMultiplicity.not_of_isUnit_left + +theorem FiniteMultiplicity.not_of_one_left (b : α) : ¬ FiniteMultiplicity 1 b := by simp + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_of_one_left := FiniteMultiplicity.not_of_one_left @[simp] theorem emultiplicity_one_left (b : α) : emultiplicity 1 b = ⊤ := - emultiplicity_eq_top.2 (Finite.not_of_one_left _) + emultiplicity_eq_top.2 (FiniteMultiplicity.not_of_one_left _) @[simp] -theorem multiplicity.Finite.one_right (ha : Finite a 1) : multiplicity a 1 = 0 := by +theorem FiniteMultiplicity.one_right (ha : FiniteMultiplicity a 1) : multiplicity a 1 = 0 := by simp [ha.multiplicity_eq_iff, ha.not_dvd_of_one_right] -theorem multiplicity.Finite.not_of_unit_left (a : α) (u : αˣ) : ¬ Finite (u : α) a := - Finite.not_of_isUnit_left a u.isUnit +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.one_right := FiniteMultiplicity.one_right + +theorem FiniteMultiplicity.not_of_unit_left (a : α) (u : αˣ) : ¬ FiniteMultiplicity (u : α) a := + FiniteMultiplicity.not_of_isUnit_left a u.isUnit + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.not_of_unit_left := FiniteMultiplicity.not_of_unit_left theorem emultiplicity_eq_zero : emultiplicity a b = 0 ↔ ¬a ∣ b := by - by_cases hf : Finite a b + by_cases hf : FiniteMultiplicity a b · rw [← ENat.coe_zero, emultiplicity_eq_coe] simp - · simpa [emultiplicity_eq_top.2 hf] using Finite.not_iff_forall.1 hf 1 + · simpa [emultiplicity_eq_top.2 hf] using FiniteMultiplicity.not_iff_forall.1 hf 1 theorem multiplicity_eq_zero : multiplicity a b = 0 ↔ ¬a ∣ b := @@ -321,7 +404,7 @@ theorem multiplicity_ne_zero : multiplicity a b ≠ 0 ↔ a ∣ b := by simp [multiplicity_eq_zero] -theorem multiplicity.Finite.exists_eq_pow_mul_and_not_dvd (hfin : Finite a b) : +theorem FiniteMultiplicity.exists_eq_pow_mul_and_not_dvd (hfin : FiniteMultiplicity a b) : ∃ c : α, b = a ^ multiplicity a b * c ∧ ¬a ∣ c := by obtain ⟨c, hc⟩ := pow_multiplicity_dvd a b refine ⟨c, hc, ?_⟩ @@ -330,6 +413,10 @@ theorem multiplicity.Finite.exists_eq_pow_mul_and_not_dvd (hfin : Finite a b) : have h₁ : a ^ (multiplicity a b + 1) ∣ b := ⟨k, hc⟩ exact (hfin.multiplicity_eq_iff.1 (by simp)).2 h₁ +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.exists_eq_pow_mul_and_not_dvd := + FiniteMultiplicity.exists_eq_pow_mul_and_not_dvd + theorem emultiplicity_le_emultiplicity_iff {c d : β} : emultiplicity a b ≤ emultiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b → c ^ n ∣ d := by classical constructor @@ -349,12 +436,17 @@ theorem emultiplicity_le_emultiplicity_iff {c d : β} : simp_all only [not_exists, Decidable.not_not, not_true_eq_false, top_le_iff, dite_eq_right_iff, ENat.coe_ne_top, imp_false, not_false_eq_true, implies_true] -theorem multiplicity.Finite.multiplicity_le_multiplicity_iff {c d : β} (hab : Finite a b) - (hcd : Finite c d) : multiplicity a b ≤ multiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b → c ^ n ∣ d := by +theorem FiniteMultiplicity.multiplicity_le_multiplicity_iff {c d : β} (hab : FiniteMultiplicity a b) + (hcd : FiniteMultiplicity c d) : + multiplicity a b ≤ multiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b → c ^ n ∣ d := by rw [← WithTop.coe_le_coe, ENat.some_eq_coe, ← hab.emultiplicity_eq_multiplicity, ← hcd.emultiplicity_eq_multiplicity] apply emultiplicity_le_emultiplicity_iff +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.multiplicity_le_multiplicity_iff := + FiniteMultiplicity.multiplicity_le_multiplicity_iff + theorem emultiplicity_eq_emultiplicity_iff {c d : β} : emultiplicity a b = emultiplicity c d ↔ ∀ n : ℕ, a ^ n ∣ b ↔ c ^ n ∣ d := ⟨fun h n => @@ -400,8 +492,8 @@ theorem dvd_iff_multiplicity_pos {a b : α} : 0 < multiplicity a b ↔ a ∣ b : theorem dvd_iff_emultiplicity_pos {a b : α} : 0 < emultiplicity a b ↔ a ∣ b := emultiplicity_pos_iff.trans dvd_iff_multiplicity_pos -theorem Nat.multiplicity_finite_iff {a b : ℕ} : Finite a b ↔ a ≠ 1 ∧ 0 < b := by - rw [← not_iff_not, Finite.not_iff_forall, not_and_or, Ne, Classical.not_not, not_lt, +theorem Nat.finiteMultiplicity_iff {a b : ℕ} : FiniteMultiplicity a b ↔ a ≠ 1 ∧ 0 < b := by + rw [← not_iff_not, FiniteMultiplicity.not_iff_forall, not_and_or, not_ne_iff, not_lt, Nat.le_zero] exact ⟨fun h => @@ -414,9 +506,12 @@ theorem Nat.multiplicity_finite_iff {a b : ℕ} : Finite a b ↔ a ≠ 1 ∧ 0 < | 0 => ha rfl | 1 => ha1 rfl | b+2 => by omega - not_lt_of_ge (le_of_dvd (Nat.pos_of_ne_zero hb) (h b)) (lt_pow_self ha_gt_one b), + not_lt_of_ge (le_of_dvd (Nat.pos_of_ne_zero hb) (h b)) (b.lt_pow_self ha_gt_one), fun h => by cases h <;> simp [*]⟩ +@[deprecated (since := "2024-11-30")] +alias Nat.multiplicity_finite_iff := Nat.finiteMultiplicity_iff + alias ⟨_, Dvd.multiplicity_pos⟩ := dvd_iff_multiplicity_pos end Monoid @@ -425,8 +520,11 @@ section CommMonoid variable [CommMonoid α] -theorem multiplicity.Finite.mul_right {a b c : α} (hf : Finite a (b * c)) : Finite a c := - (mul_comm b c ▸ hf).mul_left +theorem FiniteMultiplicity.mul_right {a b c : α} (hf : FiniteMultiplicity a (b * c)) : + FiniteMultiplicity a c := (mul_comm b c ▸ hf).mul_left + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.mul_right := FiniteMultiplicity.mul_right theorem emultiplicity_of_isUnit_right {a b : α} (ha : ¬IsUnit a) (hb : IsUnit b) : emultiplicity a b = 0 := @@ -471,10 +569,13 @@ section MonoidWithZero variable [MonoidWithZero α] -theorem multiplicity.Finite.ne_zero {a b : α} (h : Finite a b) : b ≠ 0 := +theorem FiniteMultiplicity.ne_zero {a b : α} (h : FiniteMultiplicity a b) : b ≠ 0 := let ⟨n, hn⟩ := h fun hb => by simp [hb] at hn +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.ne_zero := FiniteMultiplicity.ne_zero + @[simp] theorem emultiplicity_zero (a : α) : emultiplicity a 0 = ⊤ := emultiplicity_eq_top.2 (fun v ↦ v.ne_zero rfl) @@ -493,12 +594,15 @@ section Semiring variable [Semiring α] -theorem multiplicity.Finite.or_of_add {p a b : α} (hf : Finite p (a + b)) : - Finite p a ∨ Finite p b := by +theorem FiniteMultiplicity.or_of_add {p a b : α} (hf : FiniteMultiplicity p (a + b)) : + FiniteMultiplicity p a ∨ FiniteMultiplicity p b := by by_contra! nh obtain ⟨c, hc⟩ := hf simp_all [dvd_add] +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.or_of_add := FiniteMultiplicity.or_of_add + theorem min_le_emultiplicity_add {p a b : α} : min (emultiplicity p a) (emultiplicity p b) ≤ emultiplicity p (a + b) := by cases hm : min (emultiplicity p a) (emultiplicity p b) @@ -516,12 +620,19 @@ section Ring variable [Ring α] @[simp] -theorem multiplicity.Finite.neg_iff {a b : α} : Finite a (-b) ↔ Finite a b := by - unfold Finite +theorem FiniteMultiplicity.neg_iff {a b : α} : + FiniteMultiplicity a (-b) ↔ FiniteMultiplicity a b := by + unfold FiniteMultiplicity congr! 3 simp only [dvd_neg] -alias ⟨_, multiplicity.Finite.neg⟩ := Finite.neg_iff +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.neg_iff := FiniteMultiplicity.neg_iff + +alias ⟨_, FiniteMultiplicity.neg⟩ := FiniteMultiplicity.neg_iff + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.neg := FiniteMultiplicity.neg @[simp] theorem emultiplicity_neg (a b : α) : emultiplicity a (-b) = emultiplicity a b := by @@ -544,7 +655,7 @@ theorem Int.multiplicity_natAbs (a : ℕ) (b : ℤ) : theorem emultiplicity_add_of_gt {p a b : α} (h : emultiplicity p b < emultiplicity p a) : emultiplicity p (a + b) = emultiplicity p b := by - have : Finite p b := finite_iff_emultiplicity_ne_top.2 (by simp [·] at h) + have : FiniteMultiplicity p b := finiteMultiplicity_iff_emultiplicity_ne_top.2 (by simp [·] at h) rw [this.emultiplicity_eq_multiplicity] at * apply emultiplicity_eq_of_dvd_of_not_dvd · apply dvd_add @@ -557,18 +668,21 @@ theorem emultiplicity_add_of_gt {p a b : α} (h : emultiplicity p b < emultiplic apply pow_dvd_of_le_emultiplicity exact Order.add_one_le_of_lt h -theorem multiplicity.Finite.multiplicity_add_of_gt {p a b : α} (hf : Finite p b) +theorem FiniteMultiplicity.multiplicity_add_of_gt {p a b : α} (hf : FiniteMultiplicity p b) (h : multiplicity p b < multiplicity p a) : multiplicity p (a + b) = multiplicity p b := multiplicity_eq_of_emultiplicity_eq <| emultiplicity_add_of_gt (hf.emultiplicity_eq_multiplicity ▸ (WithTop.coe_strictMono h).trans_le multiplicity_le_emultiplicity) +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.multiplicity_add_of_gt := FiniteMultiplicity.multiplicity_add_of_gt + theorem emultiplicity_sub_of_gt {p a b : α} (h : emultiplicity p b < emultiplicity p a) : emultiplicity p (a - b) = emultiplicity p b := by rw [sub_eq_add_neg, emultiplicity_add_of_gt] <;> rw [emultiplicity_neg]; assumption theorem multiplicity_sub_of_gt {p a b : α} (h : multiplicity p b < multiplicity p a) - (hfin : Finite p b) : multiplicity p (a - b) = multiplicity p b := by + (hfin : FiniteMultiplicity p b) : multiplicity p (a - b) = multiplicity p b := by rw [sub_eq_add_neg, hfin.neg.multiplicity_add_of_gt] <;> rw [multiplicity_neg]; assumption theorem emultiplicity_add_eq_min {p a b : α} @@ -581,8 +695,8 @@ theorem emultiplicity_add_eq_min {p a b : α} · rw [emultiplicity_add_of_gt hab, min_eq_right] exact le_of_lt hab -theorem multiplicity_add_eq_min {p a b : α} (ha : Finite p a) (hb : Finite p b) - (h : multiplicity p a ≠ multiplicity p b) : +theorem multiplicity_add_eq_min {p a b : α} (ha : FiniteMultiplicity p a) + (hb : FiniteMultiplicity p b) (h : multiplicity p a ≠ multiplicity p b) : multiplicity p (a + b) = min (multiplicity p a) (multiplicity p b) := by rcases lt_trichotomy (multiplicity p a) (multiplicity p b) with (hab | _ | hab) · rw [add_comm, ha.multiplicity_add_of_gt hab, min_eq_left] @@ -599,7 +713,7 @@ variable [CancelCommMonoidWithZero α] /- Porting note: Pulled a b intro parameters since Lean parses that more easily -/ -theorem multiplicity.finite_mul_aux {p : α} (hp : Prime p) {a b : α} : +theorem finiteMultiplicity_mul_aux {p : α} (hp : Prime p) {a b : α} : ∀ {n m : ℕ}, ¬p ^ (n + 1) ∣ a → ¬p ^ (m + 1) ∣ b → ¬p ^ (n + m + 1) ∣ a * b | n, m => fun ha hb ⟨s, hs⟩ => have : p ∣ a * b := ⟨p ^ (n + m) * s, by simp [hs, pow_add, mul_comm, mul_assoc, mul_left_comm]⟩ @@ -612,7 +726,7 @@ theorem multiplicity.finite_mul_aux {p : α} (hp : Prime p) {a b : α} : rw [tsub_add_cancel_of_le (succ_le_of_lt hn0)] at hy simp [hy, pow_add, mul_comm, mul_assoc, mul_left_comm]⟩) have : 1 ≤ n + m := le_trans hn0 (Nat.le_add_right n m) - finite_mul_aux hp hpx hb + finiteMultiplicity_mul_aux hp hpx hb ⟨s, mul_right_cancel₀ hp.1 (by rw [tsub_add_eq_add_tsub (succ_le_of_lt hn0), tsub_add_cancel_of_le this] simp_all [mul_comm, mul_assoc, mul_left_comm, pow_add])⟩) @@ -626,29 +740,40 @@ theorem multiplicity.finite_mul_aux {p : α} (hp : Prime p) {a b : α} : mul_right_cancel₀ hp.1 <| by rw [tsub_add_cancel_of_le (succ_le_of_lt hm0)] at hy simp [hy, pow_add, mul_comm, mul_assoc, mul_left_comm]⟩) - finite_mul_aux hp ha hpx + finiteMultiplicity_mul_aux hp ha hpx ⟨s, mul_right_cancel₀ hp.1 (by rw [add_assoc, tsub_add_cancel_of_le (succ_le_of_lt hm0)] simp_all [mul_comm, mul_assoc, mul_left_comm, pow_add])⟩ -theorem Prime.multiplicity_finite_mul {p a b : α} (hp : Prime p) : - Finite p a → Finite p b → Finite p (a * b) := - fun ⟨n, hn⟩ ⟨m, hm⟩ => ⟨n + m, finite_mul_aux hp hn hm⟩ +@[deprecated (since := "2024-11-30")] +alias multiplicity.finite_mul_aux := finiteMultiplicity_mul_aux -theorem multiplicity.Finite.mul_iff {p a b : α} (hp : Prime p) : - Finite p (a * b) ↔ Finite p a ∧ Finite p b := +theorem Prime.finiteMultiplicity_mul {p a b : α} (hp : Prime p) : + FiniteMultiplicity p a → FiniteMultiplicity p b → FiniteMultiplicity p (a * b) := + fun ⟨n, hn⟩ ⟨m, hm⟩ => ⟨n + m, finiteMultiplicity_mul_aux hp hn hm⟩ + +@[deprecated (since := "2024-11-30")] +alias Prime.multiplicity_finite_mul := Prime.finiteMultiplicity_mul + +theorem FiniteMultiplicity.mul_iff {p a b : α} (hp : Prime p) : + FiniteMultiplicity p (a * b) ↔ FiniteMultiplicity p a ∧ FiniteMultiplicity p b := ⟨fun h => ⟨h.mul_left, h.mul_right⟩, fun h => - hp.multiplicity_finite_mul h.1 h.2⟩ + hp.finiteMultiplicity_mul h.1 h.2⟩ + +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.mul_iff := FiniteMultiplicity.mul_iff -theorem multiplicity.Finite.pow {p a : α} (hp : Prime p) - (hfin : Finite p a) {k : ℕ} : Finite p (a ^ k) := +theorem FiniteMultiplicity.pow {p a : α} (hp : Prime p) + (hfin : FiniteMultiplicity p a) {k : ℕ} : FiniteMultiplicity p (a ^ k) := match k, hfin with | 0, _ => ⟨0, by simp [mt isUnit_iff_dvd_one.2 hp.2.1]⟩ - | k + 1, ha => by rw [_root_.pow_succ']; exact hp.multiplicity_finite_mul ha (ha.pow hp) + | k + 1, ha => by rw [_root_.pow_succ']; exact hp.finiteMultiplicity_mul ha (ha.pow hp) + +@[deprecated (since := "2024-11-30")] alias multiplicity.Finite.pow := FiniteMultiplicity.pow @[simp] theorem multiplicity_self {a : α} : multiplicity a a = 1 := by - by_cases ha : Finite a a + by_cases ha : FiniteMultiplicity a a · rw [ha.multiplicity_eq_iff] simp only [pow_one, dvd_refl, reduceAdd, true_and] rintro ⟨v, hv⟩ @@ -661,11 +786,14 @@ theorem multiplicity_self {a : α} : multiplicity a a = 1 := by · simp [ha] @[simp] -theorem multiplicity.Finite.emultiplicity_self {a : α} (hfin : Finite a a) : +theorem FiniteMultiplicity.emultiplicity_self {a : α} (hfin : FiniteMultiplicity a a) : emultiplicity a a = 1 := by simp [hfin.emultiplicity_eq_multiplicity] -theorem multiplicity_mul {p a b : α} (hp : Prime p) (hfin : Finite p (a * b)) : +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.emultiplicity_self := FiniteMultiplicity.emultiplicity_self + +theorem multiplicity_mul {p a b : α} (hp : Prime p) (hfin : FiniteMultiplicity p (a * b)) : multiplicity p (a * b) = multiplicity p a + multiplicity p b := by have hdiva : p ^ multiplicity p a ∣ a := pow_multiplicity_dvd .. have hdivb : p ^ multiplicity p b ∣ b := pow_multiplicity_dvd .. @@ -681,14 +809,14 @@ theorem multiplicity_mul {p a b : α} (hp : Prime p) (hfin : Finite p (a * b)) : theorem emultiplicity_mul {p a b : α} (hp : Prime p) : emultiplicity p (a * b) = emultiplicity p a + emultiplicity p b := by - by_cases hfin : Finite p (a * b) + by_cases hfin : FiniteMultiplicity p (a * b) · rw [hfin.emultiplicity_eq_multiplicity, hfin.mul_left.emultiplicity_eq_multiplicity, hfin.mul_right.emultiplicity_eq_multiplicity] norm_cast exact multiplicity_mul hp hfin · rw [emultiplicity_eq_top.2 hfin, eq_comm, WithTop.add_eq_top, emultiplicity_eq_top, emultiplicity_eq_top] - simpa only [Finite.mul_iff hp, not_and_or] using hfin + simpa only [FiniteMultiplicity.mul_iff hp, not_and_or] using hfin theorem Finset.emultiplicity_prod {β : Type*} {p : α} (hp : Prime p) (s : Finset β) (f : β → α) : emultiplicity p (∏ x ∈ s, f x) = ∑ x ∈ s, emultiplicity p (f x) := by classical @@ -703,11 +831,14 @@ theorem emultiplicity_pow {p a : α} (hp : Prime p) {k : ℕ} : · simp [emultiplicity_of_one_right hp.not_unit] · simp [pow_succ, emultiplicity_mul hp, hk, add_mul] -protected theorem multiplicity.Finite.multiplicity_pow {p a : α} (hp : Prime p) - (ha : Finite p a) {k : ℕ} : multiplicity p (a ^ k) = k * multiplicity p a := by +protected theorem FiniteMultiplicity.multiplicity_pow {p a : α} (hp : Prime p) + (ha : FiniteMultiplicity p a) {k : ℕ} : multiplicity p (a ^ k) = k * multiplicity p a := by exact_mod_cast (ha.pow hp).emultiplicity_eq_multiplicity ▸ ha.emultiplicity_eq_multiplicity ▸ emultiplicity_pow hp +@[deprecated (since := "2024-11-30")] +alias multiplicity.Finite.multiplicity_pow := FiniteMultiplicity.multiplicity_pow + theorem emultiplicity_pow_self {p : α} (h0 : p ≠ 0) (hu : ¬IsUnit p) (n : ℕ) : emultiplicity p (p ^ n) = n := by apply emultiplicity_eq_of_dvd_of_not_dvd @@ -731,8 +862,6 @@ end CancelCommMonoidWithZero section Nat -open multiplicity - theorem multiplicity_eq_zero_of_coprime {p a b : ℕ} (hp : p ≠ 1) (hle : multiplicity p a ≤ multiplicity p b) (hab : Nat.Coprime a b) : multiplicity p a = 0 := by apply Nat.eq_zero_of_not_pos @@ -745,16 +874,29 @@ theorem multiplicity_eq_zero_of_coprime {p a b : ℕ} (hp : p ≠ 1) end Nat -theorem Int.multiplicity_finite_iff_natAbs_finite {a b : ℤ} : - Finite a b ↔ Finite a.natAbs b.natAbs := by - simp only [Finite.def, ← Int.natAbs_dvd_natAbs, Int.natAbs_pow] +theorem Int.finiteMultiplicity_iff_finiteMultiplicity_natAbs {a b : ℤ} : + FiniteMultiplicity a b ↔ FiniteMultiplicity a.natAbs b.natAbs := by + simp only [FiniteMultiplicity.def, ← Int.natAbs_dvd_natAbs, Int.natAbs_pow] + +@[deprecated (since := "2024-11-30")] +alias Int.multiplicity_finite_iff_natAbs_finite := + Int.finiteMultiplicity_iff_finiteMultiplicity_natAbs -theorem Int.multiplicity_finite_iff {a b : ℤ} : Finite a b ↔ a.natAbs ≠ 1 ∧ b ≠ 0 := by - rw [multiplicity_finite_iff_natAbs_finite, Nat.multiplicity_finite_iff, +theorem Int.finiteMultiplicity_iff {a b : ℤ} : FiniteMultiplicity a b ↔ a.natAbs ≠ 1 ∧ b ≠ 0 := by + rw [finiteMultiplicity_iff_finiteMultiplicity_natAbs, Nat.finiteMultiplicity_iff, pos_iff_ne_zero, Int.natAbs_ne_zero] -instance Nat.decidableMultiplicityFinite : DecidableRel fun a b : ℕ => Finite a b := fun _ _ => - decidable_of_iff' _ Nat.multiplicity_finite_iff +@[deprecated (since := "2024-11-30")] +alias Int.multiplicity_finite_iff := Int.finiteMultiplicity_iff + +instance Nat.decidableFiniteMultiplicity : DecidableRel fun a b : ℕ => FiniteMultiplicity a b := + fun _ _ ↦ decidable_of_iff' _ Nat.finiteMultiplicity_iff + +@[deprecated (since := "2024-11-30")] +alias Nat.decidableMultiplicityFinite := Nat.decidableFiniteMultiplicity + +instance Int.decidableMultiplicityFinite : DecidableRel fun a b : ℤ => FiniteMultiplicity a b := + fun _ _ ↦ decidable_of_iff' _ Int.finiteMultiplicity_iff -instance Int.decidableMultiplicityFinite : DecidableRel fun a b : ℤ => Finite a b := fun _ _ => - decidable_of_iff' _ Int.multiplicity_finite_iff +@[deprecated (since := "2024-11-30")] +alias Int.decidableFiniteMultiplicity := Int.decidableMultiplicityFinite diff --git a/Mathlib/RingTheory/MvPolynomial/EulerIdentity.lean b/Mathlib/RingTheory/MvPolynomial/EulerIdentity.lean new file mode 100644 index 0000000000000..80d599cc70bfb --- /dev/null +++ b/Mathlib/RingTheory/MvPolynomial/EulerIdentity.lean @@ -0,0 +1,73 @@ +/- +Copyright (c) 2024 Junyan Xu. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Junyan Xu +-/ +import Mathlib.Algebra.MvPolynomial.PDeriv +import Mathlib.RingTheory.MvPolynomial.Homogeneous + +/-! +# Euler's homogeneous identity + +## Main resutls + +* `IsHomogeneous.sum_X_mul_pderiv`: Euler's identity for homogeneous polynomials: + for a multivariate homogeneous polynomial, + the product of each variable with the derivative with respect to that variable + sums up to the degree times the polynomial. +* `IsWeightedHomogeneous.sum_weight_X_mul_pderiv`: the weighted version of Euler's identity. +-/ + +namespace MvPolynomial + +open Finsupp + +variable {R σ M : Type*} [CommSemiring R] {φ : MvPolynomial σ R} + +protected lemma IsWeightedHomogeneous.pderiv [AddCancelCommMonoid M] {w : σ → M} {n n' : M} {i : σ} + (h : φ.IsWeightedHomogeneous w n) (h' : n' + w i = n) : + (pderiv i φ).IsWeightedHomogeneous w n' := by + rw [← mem_weightedHomogeneousSubmodule, weightedHomogeneousSubmodule_eq_finsupp_supported, + Finsupp.supported_eq_span_single] at h + refine Submodule.span_induction ?_ ?_ (fun p q _ _ hp hq ↦ ?_) (fun r p _ h ↦ ?_) h + · rintro _ ⟨m, hm, rfl⟩ + simp_rw [single_eq_monomial, pderiv_monomial, one_mul] + by_cases hi : m i = 0 + · rw [hi, Nat.cast_zero, monomial_zero]; apply isWeightedHomogeneous_zero + convert isWeightedHomogeneous_monomial .. + rw [← add_right_cancel_iff (a := w i), h', ← hm, weight_sub_single_add hi] + · rw [map_zero]; apply isWeightedHomogeneous_zero + · rw [map_add]; exact hp.add hq + · rw [(pderiv i).map_smul]; exact (weightedHomogeneousSubmodule ..).smul_mem _ h + +protected lemma IsHomogeneous.pderiv {n : ℕ} {i : σ} (h : φ.IsHomogeneous n) : + (pderiv i φ).IsHomogeneous (n - 1) := by + obtain _ | n := n + · rw [← totalDegree_zero_iff_isHomogeneous, totalDegree_eq_zero_iff_eq_C] at h + rw [h, pderiv_C]; apply isHomogeneous_zero + · exact IsWeightedHomogeneous.pderiv h rfl + +variable [Fintype σ] {n : ℕ} + +open Finset in +/-- Euler's identity for weighted homogeneous polynomials. -/ +theorem IsWeightedHomogeneous.sum_weight_X_mul_pderiv {w : σ → ℕ} + (h : φ.IsWeightedHomogeneous w n) : ∑ i : σ, w i • (X i * pderiv i φ) = n • φ := by + rw [← mem_weightedHomogeneousSubmodule, weightedHomogeneousSubmodule_eq_finsupp_supported, + supported_eq_span_single] at h + refine Submodule.span_induction ?_ ?_ (fun p q _ _ hp hq ↦ ?_) (fun r p _ h ↦ ?_) h + · rintro _ ⟨m, hm, rfl⟩ + simp_rw [single_eq_monomial, X_mul_pderiv_monomial, smul_smul, ← sum_smul, mul_comm (w _)] + congr + rwa [Set.mem_setOf, weight_apply, sum_fintype] at hm + intro; apply zero_smul + · simp + · simp_rw [map_add, left_distrib, smul_add, sum_add_distrib, hp, hq] + · simp_rw [(pderiv _).map_smul, nsmul_eq_mul, mul_smul_comm, ← Finset.smul_sum, ← nsmul_eq_mul, h] + +/-- Euler's identity for homogeneous polynomials. -/ +theorem IsHomogeneous.sum_X_mul_pderiv (h : φ.IsHomogeneous n) : + ∑ i : σ, X i * pderiv i φ = n • φ := by + simp_rw [← h.sum_weight_X_mul_pderiv, Pi.one_apply, one_smul] + +end MvPolynomial diff --git a/Mathlib/RingTheory/MvPolynomial/Groebner.lean b/Mathlib/RingTheory/MvPolynomial/Groebner.lean new file mode 100644 index 0000000000000..a2149146b532f --- /dev/null +++ b/Mathlib/RingTheory/MvPolynomial/Groebner.lean @@ -0,0 +1,238 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ +import Mathlib.Data.Finsupp.Lex +import Mathlib.Data.Finsupp.MonomialOrder +import Mathlib.Data.Finsupp.WellFounded +import Mathlib.Data.List.TFAE +import Mathlib.RingTheory.MvPolynomial.Homogeneous +import Mathlib.RingTheory.MvPolynomial.MonomialOrder + +/-! # Division algorithm with respect to monomial orders + +We provide a division algorithm with respect to monomial orders in polynomial rings. +Let `R` be a commutative ring, `σ` a type of indeterminates and `m : MonomialOrder σ` +a monomial ordering on `σ →₀ ℕ`. + +Consider a family of polynomials `b : ι → MvPolynomial σ R` with invertible leading coefficients +(with respect to `m`) : we assume `hb : ∀ i, IsUnit (m.lCoeff (b i))`). + +* `MonomialOrder.div hb f` furnishes + - a finitely supported family `g : ι →₀ MvPolynomial σ R` + - and a “remainder” `r : MvPolynomial σ R` +such that the three properties hold: + (1) One has `f = ∑ (g i) * (b i) + r` + (2) For every `i`, `m.degree ((g i) * (b i)` is less than or equal to that of `f` + (3) For every `i`, every monomial in the support of `r` is strictly smaller + than the leading term of `b i`, + +The proof is done by induction, using two standard constructions + +* `MonomialOrder.subLTerm f` deletes the leading term of a polynomial `f` + +* `MonomialOrder.reduce hb f` subtracts from `f` the appropriate multiple of `b : MvPolynomial σ R`, +provided `IsUnit (m.lCoeff b)`. + +* `MonomialOrder.div_set` is the variant of `MonomialOrder.div` for a set of polynomials. + +## Reference : [Becker-Weispfenning1993] + +## TODO + +* Prove that under `Field F`, `IsUnit (m.lCoeff (b i))` is equivalent to `b i ≠ 0`. + +-/ + +namespace MonomialOrder + +open MvPolynomial + +open scoped MonomialOrder + +variable {σ : Type*} {m : MonomialOrder σ} {R : Type*} [CommRing R] + +variable (m) in +/-- Delete the leading term in a multivariate polynomial (for some monomial order) -/ +noncomputable def subLTerm (f : MvPolynomial σ R) : MvPolynomial σ R := + f - monomial (m.degree f) (m.lCoeff f) + +theorem degree_sub_LTerm_le (f : MvPolynomial σ R) : + m.degree (m.subLTerm f) ≼[m] m.degree f := by + apply le_trans degree_sub_le + simp only [sup_le_iff, le_refl, true_and] + apply degree_monomial_le + +theorem degree_sub_LTerm_lt {f : MvPolynomial σ R} (hf : m.degree f ≠ 0) : + m.degree (m.subLTerm f) ≺[m] m.degree f := by + rw [lt_iff_le_and_ne] + refine ⟨degree_sub_LTerm_le f, ?_⟩ + classical + intro hf' + simp only [EmbeddingLike.apply_eq_iff_eq] at hf' + have : m.subLTerm f ≠ 0 := by + intro h + simp only [h, degree_zero] at hf' + exact hf hf'.symm + rw [← coeff_degree_ne_zero_iff (m := m), hf'] at this + apply this + simp [subLTerm, coeff_monomial, lCoeff] + +variable (m) in +/-- Reduce a polynomial modulo a polynomial with unit leading term (for some monomial order) -/ +noncomputable def reduce {b : MvPolynomial σ R} (hb : IsUnit (m.lCoeff b)) (f : MvPolynomial σ R) : + MvPolynomial σ R := + f - monomial (m.degree f - m.degree b) (hb.unit⁻¹ * m.lCoeff f) * b + +theorem degree_reduce_lt {f b : MvPolynomial σ R} (hb : IsUnit (m.lCoeff b)) + (hbf : m.degree b ≤ m.degree f) (hf : m.degree f ≠ 0) : + m.degree (m.reduce hb f) ≺[m] m.degree f := by + have H : m.degree f = + m.degree ((monomial (m.degree f - m.degree b)) (hb.unit⁻¹ * m.lCoeff f)) + + m.degree b := by + classical + rw [degree_monomial, if_neg] + · ext d + rw [tsub_add_cancel_of_le hbf] + · simp only [Units.mul_right_eq_zero, lCoeff_eq_zero_iff] + intro hf0 + apply hf + simp [hf0] + have H' : coeff (m.degree f) (m.reduce hb f) = 0 := by + simp only [reduce, coeff_sub, sub_eq_zero] + nth_rewrite 2 [H] + rw [coeff_mul_of_degree_add (m := m), lCoeff_monomial] + rw [mul_comm, ← mul_assoc] + simp only [IsUnit.mul_val_inv, one_mul] + rfl + rw [lt_iff_le_and_ne] + constructor + · classical + apply le_trans degree_sub_le + simp only [sup_le_iff, le_refl, true_and] + apply le_of_le_of_eq degree_mul_le + rw [m.toSyn.injective.eq_iff] + exact H.symm + · intro K + simp only [EmbeddingLike.apply_eq_iff_eq] at K + nth_rewrite 1 [← K] at H' + change lCoeff m _ = 0 at H' + rw [lCoeff_eq_zero_iff] at H' + rw [H', degree_zero] at K + exact hf K.symm + +theorem div {ι : Type*} {b : ι → MvPolynomial σ R} + (hb : ∀ i, IsUnit (m.lCoeff (b i))) (f : MvPolynomial σ R) : + ∃ (g : ι →₀ (MvPolynomial σ R)) (r : MvPolynomial σ R), + f = Finsupp.linearCombination _ b g + r ∧ + (∀ i, m.degree (b i * (g i)) ≼[m] m.degree f) ∧ + (∀ c ∈ r.support, ∀ i, ¬ (m.degree (b i) ≤ c)) := by + by_cases hb' : ∃ i, m.degree (b i) = 0 + · obtain ⟨i, hb0⟩ := hb' + use Finsupp.single i ((hb i).unit⁻¹ • f), 0 + constructor + · simp only [Finsupp.linearCombination_single, smul_eq_mul, add_zero] + simp only [smul_mul_assoc, ← smul_eq_iff_eq_inv_smul, Units.smul_isUnit] + nth_rewrite 2 [eq_C_of_degree_eq_zero hb0] + rw [mul_comm, smul_eq_C_mul] + constructor + · intro j + by_cases hj : j = i + · apply le_trans degree_mul_le + simp only [hj, hb0, Finsupp.single_eq_same, zero_add] + apply le_of_eq + simp only [EmbeddingLike.apply_eq_iff_eq] + apply degree_smul (Units.isRegular _) + · simp only [Finsupp.single_eq_of_ne (Ne.symm hj), mul_zero, degree_zero, map_zero] + apply bot_le + · simp + push_neg at hb' + by_cases hf0 : f = 0 + · refine ⟨0, 0, by simp [hf0], ?_, by simp⟩ + intro b + simp only [Finsupp.coe_zero, Pi.zero_apply, mul_zero, degree_zero, map_zero] + exact bot_le + by_cases hf : ∃ i, m.degree (b i) ≤ m.degree f + · obtain ⟨i, hf⟩ := hf + have deg_reduce : m.degree (m.reduce (hb i) f) ≺[m] m.degree f := by + apply degree_reduce_lt (hb i) hf + intro hf0' + apply hb' i + simpa [hf0'] using hf + obtain ⟨g', r', H'⟩ := div hb (m.reduce (hb i) f) + use g' + + Finsupp.single i (monomial (m.degree f - m.degree (b i)) ((hb i).unit⁻¹ * m.lCoeff f)) + use r' + constructor + · rw [map_add, add_assoc, add_comm _ r', ← add_assoc, ← H'.1] + simp [reduce] + constructor + · rintro j + simp only [Finsupp.coe_add, Pi.add_apply] + rw [mul_add] + apply le_trans degree_add_le + simp only [sup_le_iff] + constructor + · exact le_trans (H'.2.1 _) (le_of_lt deg_reduce) + · classical + rw [Finsupp.single_apply] + split_ifs with hc + · apply le_trans degree_mul_le + simp only [map_add] + apply le_of_le_of_eq (add_le_add_left (degree_monomial_le _) _) + simp only [← hc] + rw [← map_add, m.toSyn.injective.eq_iff] + rw [add_tsub_cancel_of_le] + exact hf + · simp only [mul_zero, degree_zero, map_zero] + exact bot_le + · exact H'.2.2 + · push_neg at hf + suffices ∃ (g' : ι →₀ MvPolynomial σ R), ∃ r', + (m.subLTerm f = Finsupp.linearCombination (MvPolynomial σ R) b g' + r') ∧ + (∀ i, m.degree ((b i) * (g' i)) ≼[m] m.degree (m.subLTerm f)) ∧ + (∀ c ∈ r'.support, ∀ i, ¬ m.degree (b i) ≤ c) by + obtain ⟨g', r', H'⟩ := this + use g', r' + monomial (m.degree f) (m.lCoeff f) + constructor + · simp [← add_assoc, ← H'.1, subLTerm] + constructor + · exact fun b ↦ le_trans (H'.2.1 b) (degree_sub_LTerm_le f) + · intro c hc i + by_cases hc' : c ∈ r'.support + · exact H'.2.2 c hc' i + · convert hf i + classical + have := MvPolynomial.support_add hc + rw [Finset.mem_union, Classical.or_iff_not_imp_left] at this + simpa only [Finset.mem_singleton] using support_monomial_subset (this hc') + by_cases hf'0 : m.subLTerm f = 0 + · refine ⟨0, 0, by simp [hf'0], ?_, by simp⟩ + intro b + simp only [Finsupp.coe_zero, Pi.zero_apply, mul_zero, degree_zero, map_zero] + exact bot_le + · exact (div hb) (m.subLTerm f) +termination_by WellFounded.wrap + ((isWellFounded_iff m.syn fun x x_1 ↦ x < x_1).mp m.wf) (m.toSyn (m.degree f)) +decreasing_by +· exact deg_reduce +· apply degree_sub_LTerm_lt + intro hf0 + apply hf'0 + simp only [subLTerm, sub_eq_zero] + nth_rewrite 1 [eq_C_of_degree_eq_zero hf0, hf0] + simp + +theorem div_set {B : Set (MvPolynomial σ R)} + (hB : ∀ b ∈ B, IsUnit (m.lCoeff b)) (f : MvPolynomial σ R) : + ∃ (g : B →₀ (MvPolynomial σ R)) (r : MvPolynomial σ R), + f = Finsupp.linearCombination _ (fun (b : B) ↦ (b : MvPolynomial σ R)) g + r ∧ + (∀ (b : B), m.degree ((b : MvPolynomial σ R) * (g b)) ≼[m] m.degree f) ∧ + (∀ c ∈ r.support, ∀ b ∈ B, ¬ (m.degree b ≤ c)) := by + obtain ⟨g, r, H⟩ := m.div (b := fun (p : B) ↦ p) (fun b ↦ hB b b.prop) f + exact ⟨g, r, H.1, H.2.1, fun c hc b hb ↦ H.2.2 c hc ⟨b, hb⟩⟩ + +end MonomialOrder + + diff --git a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean index 64a1bbcd81c41..99cf15144c642 100644 --- a/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/Homogeneous.lean @@ -372,7 +372,7 @@ lemma exists_eval_ne_zero_of_totalDegree_le_card_aux {N : ℕ} {F : MvPolynomial have hφR : φ.natDegree < #R := by refine lt_of_lt_of_le ?_ hnR norm_cast - refine lt_of_le_of_lt (natDegree_map_le _ _) ?_ + refine lt_of_le_of_lt natDegree_map_le ?_ suffices (finSuccEquiv _ _ F).natDegree ≠ n by omega rintro rfl refine leadingCoeff_ne_zero.mpr ?_ hFn diff --git a/Mathlib/RingTheory/MvPolynomial/MonomialOrder.lean b/Mathlib/RingTheory/MvPolynomial/MonomialOrder.lean new file mode 100644 index 0000000000000..674a8ee44cb9d --- /dev/null +++ b/Mathlib/RingTheory/MvPolynomial/MonomialOrder.lean @@ -0,0 +1,388 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir +-/ +import Mathlib.RingTheory.MvPolynomial.Homogeneous +import Mathlib.Data.Finsupp.Lex +import Mathlib.Data.Finsupp.WellFounded +import Mathlib.Data.List.TFAE +import Mathlib.Data.Finsupp.MonomialOrder + +/-! # Degree and leading coefficient of polynomials with respect to a monomial order + +We consider a type `σ` of indeterminates and a commutative semiring `R` +and a monomial order `m : MonomialOrder σ`. + +* `m.degree f` is the degree of `f` for the monomial ordering `m` + +* `m.lCoeff f` is the leading coefficient of `f` for the monomial ordering `m` + +* `m.lCoeff_ne_zero_iff f` asserts that this coefficient is nonzero iff `f ≠ 0`. + +* in a field, `m.lCoeff_is_unit_iff f` asserts that this coefficient is a unit iff `f ≠ 0`. + +* `m.degree_add_le` : the `m.degree` of `f + g` is smaller than or equal to the supremum +of those of `f` and `g` + +* `m.degree_add_of_lt h` : the `m.degree` of `f + g` is equal to that of `f` +if the `m.degree` of `g` is strictly smaller than that `f` + +* `m.lCoeff_add_of_lt h`: then, the leading coefficient of `f + g` is that of `f` . + +* `m.degree_add_of_ne h` : the `m.degree` of `f + g` is equal to that the supremum +of those of `f` and `g` if they are distinct + +* `m.degree_sub_le` : the `m.degree` of `f - g` is smaller than or equal to the supremum +of those of `f` and `g` + +* `m.degree_sub_of_lt h` : the `m.degree` of `f - g` is equal to that of `f` +if the `m.degree` of `g` is strictly smaller than that `f` + +* `m.lCoeff_sub_of_lt h`: then, the leading coefficient of `f - g` is that of `f` . + +* `m.degree_mul_le`: the `m.degree` of `f * g` is smaller than or equal to the sum of those of +`f` and `g`. + +* `m.degree_mul_of_isRegular_left`, `m.degree_mul_of_isRegular_right` and `m.degree_mul` +assert the equality when the leading coefficient of `f` or `g` is regular, +or when `R` is a domain and `f` and `g` are nonzero. + +* `m.lCoeff_mul_of_isRegular_left`, `m.lCoeff_mul_of_isRegular_right` and `m.lCoeff_mul` +say that `m.lCoeff (f * g) = m.lCoeff f * m.lCoeff g` + +## Reference + +[Becker-Weispfenning1993] + +-/ + +namespace MonomialOrder + +open MvPolynomial + +open scoped MonomialOrder + +variable {σ : Type*} {m : MonomialOrder σ} + +section Semiring + +variable {R : Type*} [CommSemiring R] + +variable (m) in +/-- the degree of a multivariate polynomial with respect to a monomial ordering -/ +def degree {R : Type*} [CommSemiring R] (f : MvPolynomial σ R) : σ →₀ ℕ := + m.toSyn.symm (f.support.sup m.toSyn) + +variable (m) in +/-- the leading coefficient of a multivariate polynomial with respect to a monomial ordering -/ +def lCoeff {R : Type*} [CommSemiring R] (f : MvPolynomial σ R) : R := + f.coeff (m.degree f) + +@[simp] +theorem degree_zero : m.degree (0 : MvPolynomial σ R) = 0 := by + simp [degree] + +@[simp] +theorem lCoeff_zero : m.lCoeff (0 : MvPolynomial σ R) = 0 := by + simp [degree, lCoeff] + +theorem degree_monomial_le {d : σ →₀ ℕ} (c : R) : + m.degree (monomial d c) ≼[m] d := by + simp only [degree, AddEquiv.apply_symm_apply] + apply le_trans (Finset.sup_mono support_monomial_subset) + simp only [Finset.sup_singleton, le_refl] + +theorem degree_monomial {d : σ →₀ ℕ} (c : R) [Decidable (c = 0)] : + m.degree (monomial d c) = if c = 0 then 0 else d := by + simp only [degree, support_monomial] + split_ifs with hc <;> simp + +@[simp] +theorem lCoeff_monomial {d : σ →₀ ℕ} (c : R) : + m.lCoeff (monomial d c) = c := by + classical + simp only [lCoeff, degree_monomial] + split_ifs with hc <;> simp [hc] + +theorem degree_le_iff {f : MvPolynomial σ R} {d : σ →₀ ℕ} : + m.degree f ≼[m] d ↔ ∀ c ∈ f.support, c ≼[m] d := by + unfold degree + simp only [AddEquiv.apply_symm_apply, Finset.sup_le_iff, mem_support_iff, ne_eq] + +theorem degree_lt_iff {f : MvPolynomial σ R} {d : σ →₀ ℕ} (hd : 0 ≺[m] d) : + m.degree f ≺[m] d ↔ ∀ c ∈ f.support, c ≺[m] d := by + simp only [map_zero] at hd + unfold degree + simp only [AddEquiv.apply_symm_apply] + exact Finset.sup_lt_iff hd + +theorem le_degree {f : MvPolynomial σ R} {d : σ →₀ ℕ} (hd : d ∈ f.support) : + d ≼[m] m.degree f := by + unfold degree + simp only [AddEquiv.apply_symm_apply, Finset.le_sup hd] + +theorem coeff_eq_zero_of_lt {f : MvPolynomial σ R} {d : σ →₀ ℕ} (hd : m.degree f ≺[m] d) : + f.coeff d = 0 := by + rw [← not_le] at hd + by_contra hf + apply hd (m.le_degree (mem_support_iff.mpr hf)) +theorem lCoeff_ne_zero_iff {f : MvPolynomial σ R} : + m.lCoeff f ≠ 0 ↔ f ≠ 0 := by + constructor + · rw [not_imp_not] + intro hf + rw [hf, lCoeff_zero] + · intro hf + rw [← support_nonempty] at hf + rw [lCoeff, ← mem_support_iff, degree] + suffices f.support.sup m.toSyn ∈ m.toSyn '' f.support by + obtain ⟨d, hd, hd'⟩ := this + rw [← hd', AddEquiv.symm_apply_apply] + exact hd + exact Finset.sup_mem_of_nonempty hf + +@[simp] +theorem lCoeff_eq_zero_iff {f : MvPolynomial σ R} : + lCoeff m f = 0 ↔ f = 0 := by + simp only [← not_iff_not, lCoeff_ne_zero_iff] + +theorem coeff_degree_ne_zero_iff {f : MvPolynomial σ R} : + f.coeff (m.degree f) ≠ 0 ↔ f ≠ 0 := + m.lCoeff_ne_zero_iff + +@[simp] +theorem coeff_degree_eq_zero_iff {f : MvPolynomial σ R} : + f.coeff (m.degree f) = 0 ↔ f = 0 := + m.lCoeff_eq_zero_iff + +theorem degree_eq_zero_iff_totalDegree_eq_zero {f : MvPolynomial σ R} : + m.degree f = 0 ↔ f.totalDegree = 0 := by + rw [← m.toSyn.injective.eq_iff] + rw [map_zero, ← m.bot_eq_zero, eq_bot_iff, m.bot_eq_zero, ← m.toSyn.map_zero] + rw [degree_le_iff] + rw [totalDegree_eq_zero_iff] + apply forall_congr' + intro d + apply imp_congr (rfl.to_iff) + rw [map_zero, ← m.bot_eq_zero, ← eq_bot_iff, m.bot_eq_zero] + simp only [EmbeddingLike.map_eq_zero_iff] + exact Finsupp.ext_iff + +@[simp] +theorem degree_C (r : R) : + m.degree (C r) = 0 := by + rw [degree_eq_zero_iff_totalDegree_eq_zero, totalDegree_C] + +theorem degree_add_le {f g : MvPolynomial σ R} : + m.toSyn (m.degree (f + g)) ≤ m.toSyn (m.degree f) ⊔ m.toSyn (m.degree g) := by + conv_rhs => rw [← m.toSyn.apply_symm_apply (_ ⊔ _)] + rw [degree_le_iff] + simp only [AddEquiv.apply_symm_apply, le_sup_iff] + intro b hb + by_cases hf : b ∈ f.support + · left + exact m.le_degree hf + · right + apply m.le_degree + simp only [not_mem_support_iff] at hf + simpa only [mem_support_iff, coeff_add, hf, zero_add] using hb + +theorem degree_add_of_lt {f g : MvPolynomial σ R} (h : m.degree g ≺[m] m.degree f) : + m.degree (f + g) = m.degree f := by + apply m.toSyn.injective + apply le_antisymm + · apply le_trans degree_add_le + simp only [sup_le_iff, le_refl, true_and, le_of_lt h] + · apply le_degree + rw [mem_support_iff, coeff_add, m.coeff_eq_zero_of_lt h, add_zero, ← lCoeff, lCoeff_ne_zero_iff] + intro hf + rw [← not_le, hf] at h + apply h + simp only [degree_zero, map_zero] + apply bot_le + +theorem lCoeff_add_of_lt {f g : MvPolynomial σ R} (h : m.degree g ≺[m] m.degree f) : + m.lCoeff (f + g) = m.lCoeff f := by + simp only [lCoeff, m.degree_add_of_lt h, coeff_add, coeff_eq_zero_of_lt h, add_zero] + +theorem degree_add_of_ne {f g : MvPolynomial σ R} + (h : m.degree f ≠ m.degree g) : + m.toSyn (m.degree (f + g)) = m.toSyn (m.degree f) ⊔ m.toSyn (m.degree g) := by + by_cases h' : m.degree g ≺[m] m.degree f + · simp [degree_add_of_lt h', left_eq_sup, le_of_lt h'] + · rw [not_lt, le_iff_eq_or_lt, Classical.or_iff_not_imp_left, EmbeddingLike.apply_eq_iff_eq] at h' + rw [add_comm, degree_add_of_lt (h' h), right_eq_sup] + simp only [le_of_lt (h' h)] + +theorem degree_mul_le {f g : MvPolynomial σ R} : + m.degree (f * g) ≼[m] m.degree f + m.degree g := by + classical + rw [degree_le_iff] + intro c + rw [← not_lt, mem_support_iff, not_imp_not] + intro hc + rw [coeff_mul] + apply Finset.sum_eq_zero + rintro ⟨d, e⟩ hde + simp only [Finset.mem_antidiagonal] at hde + dsimp only + by_cases hd : m.degree f ≺[m] d + · rw [m.coeff_eq_zero_of_lt hd, zero_mul] + · suffices m.degree g ≺[m] e by + rw [m.coeff_eq_zero_of_lt this, mul_zero] + simp only [not_lt] at hd + apply lt_of_add_lt_add_left (a := m.toSyn d) + simp only [← map_add, hde] + apply lt_of_le_of_lt _ hc + simp only [map_add] + exact add_le_add_right hd _ + +/-- Multiplicativity of leading coefficients -/ +theorem coeff_mul_of_degree_add {f g : MvPolynomial σ R} : + (f * g).coeff (m.degree f + m.degree g) = m.lCoeff f * m.lCoeff g := by + classical + rw [coeff_mul] + rw [Finset.sum_eq_single (m.degree f, m.degree g)] + · rfl + · rintro ⟨c, d⟩ hcd h + simp only [Finset.mem_antidiagonal] at hcd + by_cases hf : m.degree f ≺[m] c + · rw [m.coeff_eq_zero_of_lt hf, zero_mul] + · suffices m.degree g ≺[m] d by + rw [coeff_eq_zero_of_lt this, mul_zero] + apply lt_of_add_lt_add_left (a := m.toSyn c) + simp only [← map_add, hcd] + simp only [map_add] + rw [← not_le] + intro h'; apply hf + simp only [le_iff_eq_or_lt] at h' + cases h' with + | inl h' => + simp only [← map_add, EmbeddingLike.apply_eq_iff_eq, add_left_inj] at h' + exfalso + apply h + simp only [h', Prod.mk.injEq, true_and] + simpa [h'] using hcd + | inr h' => + exact lt_of_add_lt_add_right h' + · simp + +/-- Multiplicativity of leading coefficients -/ +theorem degree_mul_of_isRegular_left {f g : MvPolynomial σ R} + (hf : IsRegular (m.lCoeff f)) (hg : g ≠ 0) : + m.degree (f * g) = m.degree f + m.degree g := by + apply m.toSyn.injective + apply le_antisymm degree_mul_le + apply le_degree + rw [mem_support_iff, coeff_mul_of_degree_add] + simp only [ne_eq, hf, IsRegular.left, IsLeftRegular.mul_left_eq_zero_iff, + lCoeff_eq_zero_iff] + exact hg + +/-- Multiplicativity of leading coefficients -/ +theorem lCoeff_mul_of_isRegular_left {f g : MvPolynomial σ R} + (hf : IsRegular (m.lCoeff f)) (hg : g ≠ 0) : + m.lCoeff (f * g) = m.lCoeff f * m.lCoeff g := by + simp only [lCoeff, degree_mul_of_isRegular_left hf hg, coeff_mul_of_degree_add] + +/-- Multiplicativity of leading coefficients -/ +theorem degree_mul_of_isRegular_right {f g : MvPolynomial σ R} + (hf : f ≠ 0) (hg : IsRegular (m.lCoeff g)) : + m.degree (f * g) = m.degree f + m.degree g := by + rw [mul_comm, m.degree_mul_of_isRegular_left hg hf, add_comm] + +/-- Multiplicativity of leading coefficients -/ +theorem lCoeff_mul_of_isRegular_right {f g : MvPolynomial σ R} + (hf : f ≠ 0) (hg : IsRegular (m.lCoeff g)) : + m.lCoeff (f * g) = m.lCoeff f * m.lCoeff g := by + simp only [lCoeff, degree_mul_of_isRegular_right hf hg, coeff_mul_of_degree_add] + +/-- Degree of product -/ +theorem degree_mul [IsDomain R] {f g : MvPolynomial σ R} (hf : f ≠ 0) (hg : g ≠ 0) : + m.degree (f * g) = m.degree f + m.degree g := + degree_mul_of_isRegular_left (isRegular_of_ne_zero (lCoeff_ne_zero_iff.mpr hf)) hg + +/-- Degree of of product -/ +theorem degree_mul_of_nonzero_mul [IsDomain R] {f g : MvPolynomial σ R} (hfg : f * g ≠ 0) : + m.degree (f * g) = m.degree f + m.degree g := + degree_mul (left_ne_zero_of_mul hfg) (right_ne_zero_of_mul hfg) + +/-- Multiplicativity of leading coefficients -/ +theorem lCoeff_mul [IsDomain R] {f g : MvPolynomial σ R} + (hf : f ≠ 0) (hg : g ≠ 0) : + m.lCoeff (f * g) = m.lCoeff f * m.lCoeff g := by + rw [lCoeff, degree_mul hf hg, ← coeff_mul_of_degree_add] + +theorem degree_smul_le {r : R} {f : MvPolynomial σ R} : + m.degree (r • f) ≼[m] m.degree f := by + rw [smul_eq_C_mul] + apply le_of_le_of_eq degree_mul_le + simp + +theorem degree_smul {r : R} (hr : IsRegular r) {f : MvPolynomial σ R} : + m.degree (r • f) = m.degree f := by + by_cases hf : f = 0 + · simp [hf] + apply m.toSyn.injective + apply le_antisymm degree_smul_le + apply le_degree + simp only [mem_support_iff, smul_eq_C_mul] + rw [← zero_add (degree m f), ← degree_C r, coeff_mul_of_degree_add] + simp [lCoeff, hr.left.mul_left_eq_zero_iff, hf] + +theorem eq_C_of_degree_eq_zero {f : MvPolynomial σ R} (hf : m.degree f = 0) : + f = C (m.lCoeff f) := by + ext d + simp only [lCoeff, hf] + classical + by_cases hd : d = 0 + · simp [hd] + · rw [coeff_C, if_neg (Ne.symm hd)] + apply coeff_eq_zero_of_lt (m := m) + rw [hf, map_zero, lt_iff_le_and_ne, ne_eq, eq_comm, EmbeddingLike.map_eq_zero_iff] + exact ⟨bot_le, hd⟩ + +end Semiring + +section Ring + +variable {R : Type*} [CommRing R] + +@[simp] +theorem degree_neg {f : MvPolynomial σ R} : + m.degree (-f) = m.degree f := by + unfold degree + rw [support_neg] + +theorem degree_sub_le {f g : MvPolynomial σ R} : + m.toSyn (m.degree (f - g)) ≤ m.toSyn (m.degree f) ⊔ m.toSyn (m.degree g) := by + rw [sub_eq_add_neg] + apply le_of_le_of_eq m.degree_add_le + rw [degree_neg] + +theorem degree_sub_of_lt {f g : MvPolynomial σ R} (h : m.degree g ≺[m] m.degree f) : + m.degree (f - g) = m.degree f := by + rw [sub_eq_add_neg] + apply degree_add_of_lt + simp only [degree_neg, h] + +theorem lCoeff_sub_of_lt {f g : MvPolynomial σ R} (h : m.degree g ≺[m] m.degree f) : + m.lCoeff (f - g) = m.lCoeff f := by + rw [sub_eq_add_neg] + apply lCoeff_add_of_lt + simp only [degree_neg, h] + +end Ring + +section Field + +variable {R : Type*} [Field R] + +theorem lCoeff_is_unit_iff {f : MvPolynomial σ R} : + IsUnit (m.lCoeff f) ↔ f ≠ 0 := by + simp only [isUnit_iff_ne_zero, ne_eq, lCoeff_eq_zero_iff] + +end Field + +end MonomialOrder diff --git a/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean b/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean index 18bd357e9e117..c0b99872fcf13 100644 --- a/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean +++ b/Mathlib/RingTheory/MvPolynomial/WeightedHomogeneous.lean @@ -251,6 +251,12 @@ theorem mul {w : σ → M} (hφ : IsWeightedHomogeneous w φ m) (hψ : IsWeighte IsWeightedHomogeneous w (φ * ψ) (m + n) := weightedHomogeneousSubmodule_mul w m n <| Submodule.mul_mem_mul hφ hψ +theorem pow {w : σ → M} (hφ : IsWeightedHomogeneous w φ m) (n : ℕ) : + IsWeightedHomogeneous w (φ ^ n) (n • m) := by + induction n with + | zero => rw [pow_zero, zero_smul]; exact isWeightedHomogeneous_one R w + | succ n ih => rw [pow_succ, succ_nsmul]; exact ih.mul hφ + /-- A product of weighted homogeneous polynomials is weighted homogeneous, with weighted degree equal to the sum of the weighted degrees. -/ theorem prod {ι : Type*} (s : Finset ι) (φ : ι → MvPolynomial σ R) (n : ι → M) {w : σ → M} : diff --git a/Mathlib/RingTheory/MvPowerSeries/PiTopology.lean b/Mathlib/RingTheory/MvPowerSeries/PiTopology.lean new file mode 100644 index 0000000000000..f3335ced2bf63 --- /dev/null +++ b/Mathlib/RingTheory/MvPowerSeries/PiTopology.lean @@ -0,0 +1,228 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir, María Inés de Frutos Fernández. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir, María Inés de Frutos Fernández +-/ + +import Mathlib.RingTheory.Nilpotent.Defs +import Mathlib.RingTheory.MvPowerSeries.Basic +import Mathlib.Topology.Algebra.InfiniteSum.Constructions +import Mathlib.Topology.Algebra.Ring.Basic +import Mathlib.Topology.Algebra.UniformGroup.Basic +import Mathlib.Topology.UniformSpace.Pi + +/-! # Product topology on multivariate power series + +Let `R` be with `Semiring R` and `TopologicalSpace R` +In this file we define the topology on `MvPowerSeries σ R` +that corresponds to the simple convergence on its coefficients. +It is the coarsest topology for which all coefficient maps are continuous. + +When `R` has `UniformSpace R`, we define the corresponding uniform structure. + +This topology can be included by writing `open scoped MvPowerSeries.WithPiTopology`. + +When the type of coefficients has the discrete topology, +it corresponds to the topology defined by [bourbaki1981], chapter 4, §4, n°2. + +It is *not* the adic topology in general. + +## Main results + +- `MvPowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_nilpotent`, + `MvPowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_zero`: if the constant coefficient + of `f` is nilpotent, or vanishes, then the powers of `f` converge to zero. + +- `MvPowerSeries.WithPiTopology.tendsto_pow_of_constantCoeff_nilpotent_iff` : the powers of `f` + converge to zero iff the constant coefficient of `f` is nilpotent. + +- `MvPowerSeries.WithPiTopology.hasSum_of_monomials_self` : viewed as an infinite sum, a power + series converges to itself. + +TODO: add the similar result for the series of homogeneous components. + +## Instances + +- If `R` is a topological (semi)ring, then so is `MvPowerSeries σ R`. +- If the topology of `R` is T0 or T2, then so is that of `MvPowerSeries σ R`. +- If `R` is a `UniformAddGroup`, then so is `MvPowerSeries σ R`. +- If `R` is complete, then so is `MvPowerSeries σ R`. + +-/ + +namespace MvPowerSeries + +open Function Filter + +variable {σ R : Type*} + +namespace WithPiTopology + +section Topology + +variable [TopologicalSpace R] + +variable (R) in +/-- The pointwise topology on `MvPowerSeries` -/ +scoped instance : TopologicalSpace (MvPowerSeries σ R) := + Pi.topologicalSpace + +/-- `MvPowerSeries` on a `T0Space` form a `T0Space` -/ +@[scoped instance] +theorem instT0Space [T0Space R] : T0Space (MvPowerSeries σ R) := Pi.instT0Space + +/-- `MvPowerSeries` on a `T2Space` form a `T2Space` -/ +@[scoped instance] +theorem instT2Space [T2Space R] : T2Space (MvPowerSeries σ R) := Pi.t2Space + +variable (R) in +/-- `MvPowerSeries.coeff` is continuous. -/ +@[fun_prop] +theorem continuous_coeff [Semiring R] (d : σ →₀ ℕ) : + Continuous (MvPowerSeries.coeff R d) := + continuous_pi_iff.mp continuous_id d + +variable (R) in +/-- `MvPolynomial.constantCoeff` is continuous -/ +theorem continuous_constantCoeff [Semiring R] : Continuous (constantCoeff σ R) := + continuous_coeff R 0 + +/-- A family of power series converges iff it converges coefficientwise -/ +theorem tendsto_iff_coeff_tendsto [Semiring R] {ι : Type*} + (f : ι → MvPowerSeries σ R) (u : Filter ι) (g : MvPowerSeries σ R) : + Tendsto f u (nhds g) ↔ + ∀ d : σ →₀ ℕ, Tendsto (fun i => coeff R d (f i)) u (nhds (coeff R d g)) := by + rw [nhds_pi, tendsto_pi] + exact forall_congr' (fun d => Iff.rfl) + +variable (σ R) + +/-- The semiring topology on `MvPowerSeries` of a topological semiring -/ +@[scoped instance] +theorem instTopologicalSemiring [Semiring R] [TopologicalSemiring R] : + TopologicalSemiring (MvPowerSeries σ R) where + continuous_add := continuous_pi fun d => continuous_add.comp + (((continuous_coeff R d).fst').prod_mk (continuous_coeff R d).snd') + continuous_mul := continuous_pi fun _ => + continuous_finset_sum _ fun i _ => continuous_mul.comp + ((continuous_coeff R i.fst).fst'.prod_mk (continuous_coeff R i.snd).snd') + +/-- The ring topology on `MvPowerSeries` of a topological ring -/ +@[scoped instance] +theorem instTopologicalRing [Ring R] [TopologicalRing R] : + TopologicalRing (MvPowerSeries σ R) := + { instTopologicalSemiring σ R with + continuous_neg := continuous_pi fun d ↦ Continuous.comp continuous_neg + (continuous_coeff R d) } + +variable {σ R} + +@[fun_prop] +theorem continuous_C [Semiring R] : + Continuous (C σ R) := by + classical + simp only [continuous_iff_continuousAt] + refine fun r ↦ (tendsto_iff_coeff_tendsto _ _ _).mpr fun d ↦ ?_ + simp only [coeff_C] + split_ifs + · exact tendsto_id + · exact tendsto_const_nhds + +theorem variables_tendsto_zero [Semiring R] : + Tendsto (X · : σ → MvPowerSeries σ R) cofinite (nhds 0) := by + classical + simp only [tendsto_iff_coeff_tendsto, ← coeff_apply, coeff_X, coeff_zero] + refine fun d ↦ tendsto_nhds_of_eventually_eq ?_ + by_cases h : ∃ i, d = Finsupp.single i 1 + · obtain ⟨i, hi⟩ := h + filter_upwards [eventually_cofinite_ne i] with j hj + simp [hi, Finsupp.single_eq_single_iff, hj.symm] + · simpa only [ite_eq_right_iff] using + Eventually.of_forall fun x h' ↦ (not_exists.mp h x h').elim + +theorem tendsto_pow_zero_of_constantCoeff_nilpotent [CommSemiring R] + {f} (hf : IsNilpotent (constantCoeff σ R f)) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) := by + classical + obtain ⟨m, hm⟩ := hf + simp_rw [tendsto_iff_coeff_tendsto, coeff_zero] + exact fun d ↦ tendsto_atTop_of_eventually_const fun n hn ↦ + coeff_eq_zero_of_constantCoeff_nilpotent hm hn + +theorem tendsto_pow_zero_of_constantCoeff_zero [CommSemiring R] + {f} (hf : constantCoeff σ R f = 0) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) := by + apply tendsto_pow_zero_of_constantCoeff_nilpotent + rw [hf] + exact IsNilpotent.zero + +/-- The powers of a `MvPowerSeries` converge to 0 iff its constant coefficient is nilpotent. +N. Bourbaki, *Algebra II*, [bourbaki1981] (chap. 4, §4, n°2, corollaire de la prop. 3) -/ +theorem tendsto_pow_of_constantCoeff_nilpotent_iff [CommRing R] [DiscreteTopology R] (f) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) ↔ + IsNilpotent (constantCoeff σ R f) := by + refine ⟨?_, tendsto_pow_zero_of_constantCoeff_nilpotent⟩ + intro h + suffices Tendsto (fun n : ℕ => constantCoeff σ R (f ^ n)) atTop (nhds 0) by + simp only [tendsto_def] at this + specialize this {0} _ + suffices ∀ x : R, {x} ∈ nhds x by exact this 0 + rw [← discreteTopology_iff_singleton_mem_nhds]; infer_instance + simp only [map_pow, mem_atTop_sets, ge_iff_le, Set.mem_preimage, + Set.mem_singleton_iff] at this + obtain ⟨m, hm⟩ := this + use m + apply hm m (le_refl m) + simp only [← @comp_apply _ R ℕ, ← tendsto_map'_iff] + simp only [Tendsto, map_le_iff_le_comap] at h ⊢ + refine le_trans h (comap_mono ?_) + rw [← map_le_iff_le_comap] + exact Continuous.continuousAt (continuous_constantCoeff R) + +variable [Semiring R] + +/-- A multivariate power series is the sum (in the sense of summable families) of its monomials -/ +theorem hasSum_of_monomials_self (f : MvPowerSeries σ R) : + HasSum (fun d : σ →₀ ℕ => monomial R d (coeff R d f)) f := by + rw [Pi.hasSum] + intro d + convert hasSum_single d ?_ using 1 + · exact (coeff_monomial_same d _).symm + · exact fun d' h ↦ coeff_monomial_ne (Ne.symm h) _ + +/-- If the coefficient space is T2, then the multivariate power series is `tsum` of its monomials -/ +theorem as_tsum [T2Space R] (f : MvPowerSeries σ R) : + f = tsum fun d : σ →₀ ℕ => monomial R d (coeff R d f) := + (HasSum.tsum_eq (hasSum_of_monomials_self _)).symm + +end Topology + +section Uniformity + +variable [UniformSpace R] + +/-- The componentwise uniformity on `MvPowerSeries` -/ +scoped instance : UniformSpace (MvPowerSeries σ R) := + Pi.uniformSpace fun _ : σ →₀ ℕ => R + +variable (R) in +/-- Coefficients of a multivariate power series are uniformly continuous -/ +theorem uniformContinuous_coeff [Semiring R] (d : σ →₀ ℕ) : + UniformContinuous fun f : MvPowerSeries σ R => coeff R d f := + uniformContinuous_pi.mp uniformContinuous_id d + +/-- Completeness of the uniform structure on `MvPowerSeries` -/ +@[scoped instance] +theorem instCompleteSpace [CompleteSpace R] : + CompleteSpace (MvPowerSeries σ R) := Pi.complete _ + +/-- The `UniformAddGroup` structure on `MvPowerSeries` of a `UniformAddGroup` -/ +@[scoped instance] +theorem instUniformAddGroup [AddGroup R] [UniformAddGroup R] : + UniformAddGroup (MvPowerSeries σ R) := Pi.instUniformAddGroup + +end Uniformity + +end WithPiTopology + +end MvPowerSeries diff --git a/Mathlib/RingTheory/Nakayama.lean b/Mathlib/RingTheory/Nakayama.lean index 5d859e8e2189a..05507c2e511a2 100644 --- a/Mathlib/RingTheory/Nakayama.lean +++ b/Mathlib/RingTheory/Nakayama.lean @@ -3,8 +3,9 @@ Copyright (c) 2021 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Chris Hughes -/ +import Mathlib.RingTheory.Finiteness.Basic import Mathlib.RingTheory.Finiteness.Nakayama -import Mathlib.RingTheory.JacobsonIdeal +import Mathlib.RingTheory.Jacobson.Ideal /-! # Nakayama's lemma diff --git a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean index b857b42737e1a..e09499939d3a0 100644 --- a/Mathlib/RingTheory/NonUnitalSubring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubring/Basic.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Jireh Loreaux -/ import Mathlib.Algebra.Group.Subgroup.Basic +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.GroupTheory.Subsemigroup.Center import Mathlib.RingTheory.NonUnitalSubring.Defs import Mathlib.RingTheory.NonUnitalSubsemiring.Basic @@ -391,6 +392,7 @@ theorem closure_le {s : Set R} {t : NonUnitalSubring R} : closure s ≤ t ↔ s /-- `NonUnitalSubring` closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set R⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Set.Subset.trans h subset_closure diff --git a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean index 71ae33dcc8107..a9859dcb69aec 100644 --- a/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean +++ b/Mathlib/RingTheory/NonUnitalSubsemiring/Basic.lean @@ -330,6 +330,7 @@ theorem closure_le {s : Set R} {t : NonUnitalSubsemiring R} : closure s ≤ t /-- Subsemiring closure of a set is monotone in its argument: if `s ⊆ t`, then `closure s ≤ closure t`. -/ +@[gcongr] theorem closure_mono ⦃s t : Set R⦄ (h : s ⊆ t) : closure s ≤ closure t := closure_le.2 <| Set.Subset.trans h subset_closure diff --git a/Mathlib/RingTheory/Nullstellensatz.lean b/Mathlib/RingTheory/Nullstellensatz.lean index 71d381cfeb340..a0a41f1573af9 100644 --- a/Mathlib/RingTheory/Nullstellensatz.lean +++ b/Mathlib/RingTheory/Nullstellensatz.lean @@ -3,7 +3,7 @@ Copyright (c) 2021 Devon Tuma. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Devon Tuma -/ -import Mathlib.RingTheory.Jacobson +import Mathlib.RingTheory.Jacobson.Ring import Mathlib.FieldTheory.IsAlgClosed.Basic import Mathlib.RingTheory.MvPolynomial import Mathlib.RingTheory.PrimeSpectrum @@ -96,17 +96,14 @@ theorem mem_vanishingIdeal_singleton_iff (x : σ → k) (p : MvPolynomial σ k) instance vanishingIdeal_singleton_isMaximal {x : σ → k} : (vanishingIdeal {x} : Ideal (MvPolynomial σ k)).IsMaximal := by - have : MvPolynomial σ k ⧸ vanishingIdeal {x} ≃+* k := - RingEquiv.ofBijective - (Ideal.Quotient.lift _ (eval x) fun p h => (mem_vanishingIdeal_singleton_iff x p).mp h) - (by - refine - ⟨(injective_iff_map_eq_zero _).mpr fun p hp => ?_, fun z => - ⟨(Ideal.Quotient.mk (vanishingIdeal {x} : Ideal (MvPolynomial σ k))) (C z), by simp⟩⟩ - obtain ⟨q, rfl⟩ := Ideal.Quotient.mk_surjective p - rwa [Ideal.Quotient.lift_mk, ← mem_vanishingIdeal_singleton_iff, - ← Quotient.eq_zero_iff_mem] at hp) - rw [← bot_quotient_isMaximal_iff, RingEquiv.bot_maximal_iff this] + have : Function.Bijective + (Ideal.Quotient.lift _ (eval x) fun p h ↦ (mem_vanishingIdeal_singleton_iff x p).mp h) := by + refine ⟨(injective_iff_map_eq_zero _).mpr fun p hp ↦ ?_, fun z ↦ + ⟨(Ideal.Quotient.mk (vanishingIdeal {x} : Ideal (MvPolynomial σ k))) (C z), by simp⟩⟩ + obtain ⟨q, rfl⟩ := Ideal.Quotient.mk_surjective p + rwa [Ideal.Quotient.lift_mk, ← mem_vanishingIdeal_singleton_iff, + ← Quotient.eq_zero_iff_mem] at hp + rw [← bot_quotient_isMaximal_iff, isMaximal_iff_of_bijective _ this] exact bot_isMaximal theorem radical_le_vanishingIdeal_zeroLocus (I : Ideal (MvPolynomial σ k)) : diff --git a/Mathlib/RingTheory/PiTensorProduct.lean b/Mathlib/RingTheory/PiTensorProduct.lean index 59dfb88d4b256..26d7db3188d1e 100644 --- a/Mathlib/RingTheory/PiTensorProduct.lean +++ b/Mathlib/RingTheory/PiTensorProduct.lean @@ -272,6 +272,11 @@ noncomputable def constantBaseRingEquiv : (⨂[R] _ : ι, R) ≃ₐ[R] R := toFun ((lift.tprod _).trans Finset.prod_const_one) (by + -- one of these is required, the other is a performance optimization + letI : IsScalarTower R (⨂[R] x : ι, R) (⨂[R] x : ι, R) := + IsScalarTower.right (R := R) (A := ⨂[R] (x : ι), R) + letI : SMulCommClass R (⨂[R] x : ι, R) (⨂[R] x : ι, R) := + Algebra.to_smulCommClass (R := R) (A := ⨂[R] x : ι, R) rw [LinearMap.map_mul_iff] ext x y show toFun (tprod R x * tprod R y) = toFun (tprod R x) * toFun (tprod R y) diff --git a/Mathlib/RingTheory/Polynomial/Basic.lean b/Mathlib/RingTheory/Polynomial/Basic.lean index 4bee44c7de8c5..5513563c4b0da 100644 --- a/Mathlib/RingTheory/Polynomial/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Basic.lean @@ -750,37 +750,6 @@ theorem is_fg_degreeLE [IsNoetherianRing R] (I : Ideal R[X]) (n : ℕ) : isNoetherian_submodule_left.1 (isNoetherian_of_fg_of_noetherian _ ⟨_, degreeLE_eq_span_X_pow.symm⟩) _ -open Algebra in -lemma _root_.Algebra.mem_ideal_map_adjoin {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] - (x : S) (I : Ideal R) {y : adjoin R ({x} : Set S)} : - y ∈ I.map (algebraMap R (adjoin R ({x} : Set S))) ↔ - ∃ p : R[X], (∀ i, p.coeff i ∈ I) ∧ Polynomial.aeval x p = y := by - constructor - · intro H - induction' H using Submodule.span_induction with a ha a b ha hb ha' hb' a b hb hb' - · obtain ⟨a, ha, rfl⟩ := ha - exact ⟨C a, fun i ↦ by rw [coeff_C]; aesop, aeval_C _ _⟩ - · exact ⟨0, by simp, aeval_zero _⟩ - · obtain ⟨a, ha, ha'⟩ := ha' - obtain ⟨b, hb, hb'⟩ := hb' - exact ⟨a + b, fun i ↦ by simpa using add_mem (ha i) (hb i), by simp [ha', hb']⟩ - · obtain ⟨b', hb, hb'⟩ := hb' - obtain ⟨a, ha⟩ := a - rw [Algebra.adjoin_singleton_eq_range_aeval] at ha - obtain ⟨p, hp : aeval x p = a⟩ := ha - refine ⟨p * b', fun i ↦ ?_, by simp [hp, hb']⟩ - rw [coeff_mul] - exact sum_mem fun i hi ↦ Ideal.mul_mem_left _ _ (hb _) - · rintro ⟨p, hp, hp'⟩ - have : y = ∑ i in p.support, p.coeff i • ⟨_, (X ^ i).aeval_mem_adjoin_singleton _ x⟩ := by - trans ∑ i in p.support, ⟨_, (C (p.coeff i) * X ^ i).aeval_mem_adjoin_singleton _ x⟩ - · ext1 - simp only [AddSubmonoidClass.coe_finset_sum, ← map_sum, ← hp', ← as_sum_support_C_mul_X_pow] - · congr with i - simp [Algebra.smul_def] - simp_rw [this, Algebra.smul_def] - exact sum_mem fun i _ ↦ Ideal.mul_mem_right _ _ (Ideal.mem_map_of_mem _ (hp i)) - end CommRing end Ideal diff --git a/Mathlib/RingTheory/Polynomial/Chebyshev.lean b/Mathlib/RingTheory/Polynomial/Chebyshev.lean index 4e9eb5a7fe9d2..c795e148a61ce 100644 --- a/Mathlib/RingTheory/Polynomial/Chebyshev.lean +++ b/Mathlib/RingTheory/Polynomial/Chebyshev.lean @@ -16,16 +16,21 @@ with integral coefficients. * `Polynomial.Chebyshev.T`: the Chebyshev polynomials of the first kind. * `Polynomial.Chebyshev.U`: the Chebyshev polynomials of the second kind. +* `Polynomial.Chebyshev.C`: the rescaled Chebyshev polynomials of the first kind (also known as the + Vieta–Lucas polynomials), given by $C_n(2x) = 2T_n(x)$. +* `Polynomial.Chebyshev.S`: the rescaled Chebyshev polynomials of the second kind (also known as the + Vieta–Fibonacci polynomials), given by $S_n(2x) = U_n(x)$. ## Main statements * The formal derivative of the Chebyshev polynomials of the first kind is a scalar multiple of the Chebyshev polynomials of the second kind. -* `Polynomial.Chebyshev.mul_T`, twice the product of the `m`-th and `k`-th Chebyshev polynomials of - the first kind is the sum of the `m + k`-th and `m - k`-th Chebyshev polynomials of the first - kind. +* `Polynomial.Chebyshev.T_mul_T`, twice the product of the `m`-th and `k`-th Chebyshev polynomials + of the first kind is the sum of the `m + k`-th and `m - k`-th Chebyshev polynomials of the first + kind. There is a similar statement `Polynomial.Chebyshev.C_mul_C` for the `C` polynomials. * `Polynomial.Chebyshev.T_mul`, the `(m * n)`-th Chebyshev polynomial of the first kind is the - composition of the `m`-th and `n`-th Chebyshev polynomials of the first kind. + composition of the `m`-th and `n`-th Chebyshev polynomials of the first kind. There is a similar + statement `Polynomial.Chebyshev.C_mul` for the `C` polynomials. ## Implementation details @@ -53,7 +58,7 @@ namespace Polynomial.Chebyshev open Polynomial -variable (R S : Type*) [CommRing R] [CommRing S] +variable (R R' : Type*) [CommRing R] [CommRing R'] /-- `T n` is the `n`-th Chebyshev polynomial of the first kind. -/ -- Well-founded definitions are now irreducible by default; @@ -100,7 +105,7 @@ theorem T_zero : T R 0 = 1 := rfl @[simp] theorem T_one : T R 1 = X := rfl -theorem T_neg_one : T R (-1) = X := (by ring : 2 * X * 1 - X = X) +theorem T_neg_one : T R (-1) = X := show 2 * X * 1 - X = X by ring theorem T_two : T R 2 = 2 * X ^ 2 - 1 := by simpa [pow_two, mul_assoc] using T_add_two R 0 @@ -217,10 +222,195 @@ theorem one_sub_X_sq_mul_U_eq_pol_in_T (n : ℤ) : (1 - X ^ 2) * U R n = X * T R (n + 1) - T R (n + 2) := by linear_combination T_eq_X_mul_T_sub_pol_U R n -variable {R S} +/-- `C n` is the `n`th rescaled Chebyshev polynomial of the first kind (also known as a Vieta–Lucas +polynomial), given by $C_n(2x) = 2T_n(x)$. See `Polynomial.Chebyshev.C_comp_two_mul_X`. -/ +@[semireducible] noncomputable def C : ℤ → R[X] + | 0 => 2 + | 1 => X + | (n : ℕ) + 2 => X * C (n + 1) - C n + | -((n : ℕ) + 1) => X * C (-n) - C (-n + 1) + termination_by n => Int.natAbs n + Int.natAbs (n - 1) + +@[simp] +theorem C_add_two : ∀ n, C R (n + 2) = X * C R (n + 1) - C R n + | (k : ℕ) => C.eq_3 R k + | -(k + 1 : ℕ) => by linear_combination (norm := (simp [Int.negSucc_eq]; ring_nf)) C.eq_4 R k + +theorem C_add_one (n : ℤ) : C R (n + 1) = X * C R n - C R (n - 1) := by + linear_combination (norm := ring_nf) C_add_two R (n - 1) + +theorem C_sub_two (n : ℤ) : C R (n - 2) = X * C R (n - 1) - C R n := by + linear_combination (norm := ring_nf) C_add_two R (n - 2) + +theorem C_sub_one (n : ℤ) : C R (n - 1) = X * C R n - C R (n + 1) := by + linear_combination (norm := ring_nf) C_add_two R (n - 1) + +theorem C_eq (n : ℤ) : C R n = X * C R (n - 1) - C R (n - 2) := by + linear_combination (norm := ring_nf) C_add_two R (n - 2) + +@[simp] +theorem C_zero : C R 0 = 2 := rfl + +@[simp] +theorem C_one : C R 1 = X := rfl + +theorem C_neg_one : C R (-1) = X := show X * 2 - X = X by ring + +theorem C_two : C R 2 = X ^ 2 - 2 := by + simpa [pow_two, mul_assoc] using C_add_two R 0 @[simp] -theorem map_T (f : R →+* S) (n : ℤ) : map f (T R n) = T S n := by +theorem C_neg (n : ℤ) : C R (-n) = C R n := by + induction n using Polynomial.Chebyshev.induct with + | zero => rfl + | one => show X * 2 - X = X; ring + | add_two n ih1 ih2 => + have h₁ := C_add_two R n + have h₂ := C_sub_two R (-n) + linear_combination (norm := ring_nf) (X:R[X]) * ih1 - ih2 - h₁ + h₂ + | neg_add_one n ih1 ih2 => + have h₁ := C_add_one R n + have h₂ := C_sub_one R (-n) + linear_combination (norm := ring_nf) (X:R[X]) * ih1 - ih2 + h₁ - h₂ + +theorem C_natAbs (n : ℤ) : C R n.natAbs = C R n := by + obtain h | h := Int.natAbs_eq n <;> nth_rw 2 [h]; simp + +theorem C_neg_two : C R (-2) = X ^ 2 - 2 := by simp [C_two] + +theorem C_comp_two_mul_X (n : ℤ) : (C R n).comp (2 * X) = 2 * T R n := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two n ih1 ih2 => + simp_rw [C_add_two, T_add_two, sub_comp, mul_comp, X_comp, ih1, ih2] + ring + | neg_add_one n ih1 ih2 => + simp_rw [C_sub_one, T_sub_one, sub_comp, mul_comp, X_comp, ih1, ih2] + ring + +theorem C_eq_two_mul_T_comp_half_mul_X [Invertible (2 : R)] (n : ℤ) : + C R n = 2 * (T R n).comp (Polynomial.C ⅟2 * X) := by + have := congr_arg (·.comp (Polynomial.C ⅟2 * X)) (C_comp_two_mul_X R n) + simp_rw [comp_assoc, mul_comp, ofNat_comp, X_comp, ← mul_assoc, ← C_eq_natCast, ← C_mul, + Nat.cast_ofNat, mul_invOf_self', map_one, one_mul, comp_X, map_ofNat] at this + assumption + +theorem T_eq_half_mul_C_comp_two_mul_X [Invertible (2 : R)] (n : ℤ) : + T R n = Polynomial.C ⅟2 * (C R n).comp (2 * X) := by + rw [C_comp_two_mul_X, ← mul_assoc, ← map_ofNat Polynomial.C 2, ← map_mul, invOf_mul_self', + map_one, one_mul] + +/-- `S n` is the `n`th rescaled Chebyshev polynomial of the second kind (also known as a +Vieta–Fibonacci polynomial), given by $S_n(2x) = U_n(x)$. See +`Polynomial.Chebyshev.S_comp_two_mul_X`. -/ +@[semireducible] noncomputable def S : ℤ → R[X] + | 0 => 1 + | 1 => X + | (n : ℕ) + 2 => X * S (n + 1) - S n + | -((n : ℕ) + 1) => X * S (-n) - S (-n + 1) + termination_by n => Int.natAbs n + Int.natAbs (n - 1) + +@[simp] +theorem S_add_two : ∀ n, S R (n + 2) = X * S R (n + 1) - S R n + | (k : ℕ) => S.eq_3 R k + | -(k + 1 : ℕ) => by linear_combination (norm := (simp [Int.negSucc_eq]; ring_nf)) S.eq_4 R k + +theorem S_add_one (n : ℤ) : S R (n + 1) = X * S R n - S R (n - 1) := by + linear_combination (norm := ring_nf) S_add_two R (n - 1) + +theorem S_sub_two (n : ℤ) : S R (n - 2) = X * S R (n - 1) - S R n := by + linear_combination (norm := ring_nf) S_add_two R (n - 2) + +theorem S_sub_one (n : ℤ) : S R (n - 1) = X * S R n - S R (n + 1) := by + linear_combination (norm := ring_nf) S_add_two R (n - 1) + +theorem S_eq (n : ℤ) : S R n = X * S R (n - 1) - S R (n - 2) := by + linear_combination (norm := ring_nf) S_add_two R (n - 2) + +@[simp] +theorem S_zero : S R 0 = 1 := rfl + +@[simp] +theorem S_one : S R 1 = X := rfl + +@[simp] +theorem S_neg_one : S R (-1) = 0 := by simpa using S_sub_one R 0 + +theorem S_two : S R 2 = X ^ 2 - 1 := by + have := S_add_two R 0 + simp only [zero_add, S_one, S_zero] at this + linear_combination this + +@[simp] +theorem S_neg_two : S R (-2) = -1 := by + simpa [zero_sub, Int.reduceNeg, S_neg_one, mul_zero, S_zero] using S_sub_two R 0 + +theorem S_neg_sub_one (n : ℤ) : S R (-n - 1) = -S R (n - 1) := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two n ih1 ih2 => + have h₁ := S_add_one R n + have h₂ := S_sub_two R (-n - 1) + linear_combination (norm := ring_nf) (X:R[X]) * ih1 - ih2 + h₁ + h₂ + | neg_add_one n ih1 ih2 => + have h₁ := S_eq R n + have h₂ := S_sub_two R (-n) + linear_combination (norm := ring_nf) (X:R[X]) * ih1 - ih2 + h₁ + h₂ + +theorem S_neg (n : ℤ) : S R (-n) = -S R (n - 2) := by simpa [sub_sub] using S_neg_sub_one R (n - 1) + +@[simp] +theorem S_neg_sub_two (n : ℤ) : S R (-n - 2) = -S R n := by + simpa [sub_eq_add_neg, add_comm] using S_neg R (n + 2) + +theorem S_comp_two_mul_X (n : ℤ) : (S R n).comp (2 * X) = U R n := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two n ih1 ih2 => simp_rw [U_add_two, S_add_two, sub_comp, mul_comp, X_comp, ih1, ih2] + | neg_add_one n ih1 ih2 => simp_rw [U_sub_one, S_sub_one, sub_comp, mul_comp, X_comp, ih1, ih2] + +theorem S_sq_add_S_sq (n : ℤ) : S R n ^ 2 + S R (n + 1) ^ 2 - X * S R n * S R (n + 1) = 1 := by + induction n using Int.induction_on with + | hz => simp; ring + | hp n ih => + have h₁ := S_add_two R n + linear_combination (norm := ring_nf) (S R (2 + n) - S R n) * h₁ + ih + | hn n ih => + have h₁ := S_sub_one R (-n) + linear_combination (norm := ring_nf) (S R (-1 - n) - S R (1 - n)) * h₁ + ih + +theorem S_eq_U_comp_half_mul_X [Invertible (2 : R)] (n : ℤ) : + S R n = (U R n).comp (Polynomial.C ⅟2 * X) := by + have := congr_arg (·.comp (Polynomial.C ⅟2 * X)) (S_comp_two_mul_X R n) + simp_rw [comp_assoc, mul_comp, ofNat_comp, X_comp, ← mul_assoc, ← C_eq_natCast, ← C_mul, + Nat.cast_ofNat, mul_invOf_self', map_one, one_mul, comp_X] at this + assumption + +theorem S_eq_X_mul_S_add_C (n : ℤ) : 2 * S R (n + 1) = X * S R n + C R (n + 1) := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp [two_mul] + | one => simp [S_two, C_two]; ring + | add_two n ih1 ih2 => + have h₁ := S_add_two R (n + 1) + have h₂ := S_add_two R n + have h₃ := C_add_two R (n + 1) + linear_combination (norm := ring_nf) -h₃ - (X:R[X]) * h₂ + 2 * h₁ + (X:R[X]) * ih1 - ih2 + | neg_add_one n ih1 ih2 => + have h₁ := S_add_two R (-n - 1) + have h₂ := S_add_two R (-n) + have h₃ := C_add_two R (-n) + linear_combination (norm := ring_nf) -h₃ + 2 * h₂ - (X:R[X]) * h₁ - ih2 + (X:R[X]) * ih1 + +theorem C_eq_S_sub_X_mul_S (n : ℤ) : C R n = 2 * S R n - X * S R (n - 1) := by + linear_combination (norm := ring_nf) - S_eq_X_mul_S_add_C R (n - 1) + +variable {R R'} + +@[simp] +theorem map_T (f : R →+* R') (n : ℤ) : map f (T R n) = T R' n := by induction n using Polynomial.Chebyshev.induct with | zero => simp | one => simp @@ -232,7 +422,7 @@ theorem map_T (f : R →+* S) (n : ℤ) : map f (T R n) = T S n := by ih2] @[simp] -theorem map_U (f : R →+* S) (n : ℤ) : map f (U R n) = U S n := by +theorem map_U (f : R →+* R') (n : ℤ) : map f (U R n) = U R' n := by induction n using Polynomial.Chebyshev.induct with | zero => simp | one => simp @@ -243,6 +433,26 @@ theorem map_U (f : R →+* S) (n : ℤ) : map f (U R n) = U S n := by simp_rw [U_sub_one, Polynomial.map_sub, Polynomial.map_mul, Polynomial.map_ofNat, map_X, ih1, ih2] +@[simp] +theorem map_C (f : R →+* R') (n : ℤ) : map f (C R n) = C R' n := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two n ih1 ih2 => + simp_rw [C_add_two, Polynomial.map_sub, Polynomial.map_mul, map_X, ih1, ih2] + | neg_add_one n ih1 ih2 => + simp_rw [C_sub_one, Polynomial.map_sub, Polynomial.map_mul, map_X, ih1, ih2] + +@[simp] +theorem map_S (f : R →+* R') (n : ℤ) : map f (S R n) = S R' n := by + induction n using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two n ih1 ih2 => + simp_rw [S_add_two, Polynomial.map_sub, Polynomial.map_mul, map_X, ih1, ih2] + | neg_add_one n ih1 ih2 => + simp_rw [S_sub_one, Polynomial.map_sub, Polynomial.map_mul, map_X, ih1, ih2] + theorem T_derivative_eq_U (n : ℤ) : derivative (T R n) = n * U R (n - 1) := by induction n using Polynomial.Chebyshev.induct with | zero => simp @@ -284,7 +494,7 @@ variable (R) /-- Twice the product of two Chebyshev `T` polynomials is the sum of two other Chebyshev `T` polynomials. -/ -theorem mul_T (m k : ℤ) : 2 * T R m * T R k = T R (m + k) + T R (m - k) := by +theorem T_mul_T (m k : ℤ) : 2 * T R m * T R k = T R (m + k) + T R (m - k) := by induction k using Polynomial.Chebyshev.induct with | zero => simp [two_mul] | one => rw [T_add_one, T_one]; ring @@ -299,20 +509,55 @@ theorem mul_T (m k : ℤ) : 2 * T R m * T R k = T R (m + k) + T R (m - k) := by have h₃ := T_add_two R (-k - 1) linear_combination (norm := ring_nf) 2 * T R m * h₃ - h₂ - h₁ - ih2 + 2 * (X : R[X]) * ih1 +@[deprecated (since := "2024-12-03")] alias mul_T := T_mul_T + +/-- The product of two Chebyshev `C` polynomials is the sum of two other Chebyshev `C` polynomials. +-/ +theorem C_mul_C (m k : ℤ) : C R m * C R k = C R (m + k) + C R (m - k) := by + induction k using Polynomial.Chebyshev.induct with + | zero => simp [mul_two] + | one => rw [C_add_one, C_one]; ring + | add_two k ih1 ih2 => + have h₁ := C_add_two R (m + k) + have h₂ := C_sub_two R (m - k) + have h₃ := C_add_two R k + linear_combination (norm := ring_nf) C R m * h₃ - h₂ - h₁ - ih2 + (X:R[X]) * ih1 + | neg_add_one k ih1 ih2 => + have h₁ := C_add_two R (m + (-k - 1)) + have h₂ := C_sub_two R (m - (-k - 1)) + have h₃ := C_add_two R (-k - 1) + linear_combination (norm := ring_nf) C R m * h₃ - h₂ - h₁ - ih2 + (X:R[X]) * ih1 + /-- The `(m * n)`-th Chebyshev `T` polynomial is the composition of the `m`-th and `n`-th. -/ theorem T_mul (m n : ℤ) : T R (m * n) = (T R m).comp (T R n) := by induction m using Polynomial.Chebyshev.induct with | zero => simp | one => simp | add_two m ih1 ih2 => - have h₁ := mul_T R ((m + 1) * n) n + have h₁ := T_mul_T R ((m + 1) * n) n have h₂ := congr_arg (comp · (T R n)) <| T_add_two R m simp only [sub_comp, mul_comp, ofNat_comp, X_comp] at h₂ linear_combination (norm := ring_nf) -ih2 - h₂ - h₁ + 2 * T R n * ih1 | neg_add_one m ih1 ih2 => - have h₁ := mul_T R ((-m) * n) n + have h₁ := T_mul_T R ((-m) * n) n have h₂ := congr_arg (comp · (T R n)) <| T_add_two R (-m - 1) simp only [sub_comp, mul_comp, ofNat_comp, X_comp] at h₂ linear_combination (norm := ring_nf) -ih2 - h₂ - h₁ + 2 * T R n * ih1 +/-- The `(m * n)`-th Chebyshev `C` polynomial is the composition of the `m`-th and `n`-th. -/ +theorem C_mul (m n : ℤ) : C R (m * n) = (C R m).comp (C R n) := by + induction m using Polynomial.Chebyshev.induct with + | zero => simp + | one => simp + | add_two m ih1 ih2 => + have h₁ := C_mul_C R ((m + 1) * n) n + have h₂ := congr_arg (comp · (C R n)) <| C_add_two R m + simp only [sub_comp, mul_comp, X_comp] at h₂ + linear_combination (norm := ring_nf) -ih2 - h₂ - h₁ + C R n * ih1 + | neg_add_one m ih1 ih2 => + have h₁ := C_mul_C R ((-m) * n) n + have h₂ := congr_arg (comp · (C R n)) <| C_add_two R (-m - 1) + simp only [sub_comp, mul_comp, X_comp] at h₂ + linear_combination (norm := ring_nf) -ih2 - h₂ - h₁ + C R n * ih1 + end Polynomial.Chebyshev diff --git a/Mathlib/RingTheory/Polynomial/Dickson.lean b/Mathlib/RingTheory/Polynomial/Dickson.lean index 1872e6ac8a9e2..b563e9a572c2a 100644 --- a/Mathlib/RingTheory/Polynomial/Dickson.lean +++ b/Mathlib/RingTheory/Polynomial/Dickson.lean @@ -135,25 +135,45 @@ private theorem two_mul_C_half_eq_one [Invertible (2 : R)] : 2 * C (⅟ 2 : R) = private theorem C_half_mul_two_eq_one [Invertible (2 : R)] : C (⅟ 2 : R) * 2 = 1 := by rw [mul_comm, two_mul_C_half_eq_one] -theorem dickson_one_one_eq_chebyshev_T [Invertible (2 : R)] : - ∀ n, dickson 1 (1 : R) n = 2 * (Chebyshev.T R n).comp (C (⅟ 2) * X) +theorem dickson_one_one_eq_chebyshev_C : ∀ n, dickson 1 (1 : R) n = Chebyshev.C R n | 0 => by - simp only [Chebyshev.T_zero, mul_one, one_comp, dickson_zero] + simp only [Chebyshev.C_zero, mul_one, one_comp, dickson_zero] norm_num | 1 => by - rw [dickson_one, Nat.cast_one, Chebyshev.T_one, X_comp, ← mul_assoc, two_mul_C_half_eq_one, - one_mul] + rw [dickson_one, Nat.cast_one, Chebyshev.C_one] | n + 2 => by - rw [dickson_add_two, C_1, Nat.cast_add, Nat.cast_two, Chebyshev.T_add_two, - dickson_one_one_eq_chebyshev_T (n + 1), dickson_one_one_eq_chebyshev_T n, sub_comp, mul_comp, - mul_comp, X_comp, ofNat_comp] - simp_rw [← mul_assoc, Nat.cast_ofNat, two_mul_C_half_eq_one, Nat.cast_add, Nat.cast_one] + rw [dickson_add_two, C_1, Nat.cast_add, Nat.cast_two, Chebyshev.C_add_two, + dickson_one_one_eq_chebyshev_C (n + 1), dickson_one_one_eq_chebyshev_C n] + push_cast ring +theorem dickson_one_one_eq_chebyshev_T [Invertible (2 : R)] (n : ℕ) : + dickson 1 (1 : R) n = 2 * (Chebyshev.T R n).comp (C (⅟ 2) * X) := + (dickson_one_one_eq_chebyshev_C R n).trans (Chebyshev.C_eq_two_mul_T_comp_half_mul_X R n) + theorem chebyshev_T_eq_dickson_one_one [Invertible (2 : R)] (n : ℕ) : - Chebyshev.T R n = C (⅟ 2) * (dickson 1 1 n).comp (2 * X) := by - rw [dickson_one_one_eq_chebyshev_T, mul_comp, ofNat_comp, comp_assoc, mul_comp, C_comp, X_comp] - simp_rw [← mul_assoc, Nat.cast_ofNat, C_half_mul_two_eq_one, one_mul, comp_X] + Chebyshev.T R n = C (⅟ 2) * (dickson 1 1 n).comp (2 * X) := + dickson_one_one_eq_chebyshev_C R n ▸ Chebyshev.T_eq_half_mul_C_comp_two_mul_X R n + +theorem dickson_two_one_eq_chebyshev_S : ∀ n, dickson 2 (1 : R) n = Chebyshev.S R n + | 0 => by + simp only [Chebyshev.S_zero, mul_one, one_comp, dickson_zero] + norm_num + | 1 => by + rw [dickson_one, Nat.cast_one, Chebyshev.S_one] + | n + 2 => by + rw [dickson_add_two, C_1, Nat.cast_add, Nat.cast_two, Chebyshev.S_add_two, + dickson_two_one_eq_chebyshev_S (n + 1), dickson_two_one_eq_chebyshev_S n] + push_cast + ring + +theorem dickson_two_one_eq_chebyshev_U [Invertible (2 : R)] (n : ℕ) : + dickson 2 (1 : R) n = (Chebyshev.U R n).comp (C (⅟ 2) * X) := + (dickson_two_one_eq_chebyshev_S R n).trans (Chebyshev.S_eq_U_comp_half_mul_X R n) + +theorem chebyshev_U_eq_dickson_two_one (n : ℕ) : + Chebyshev.U R n = (dickson 2 (1 : R) n).comp (2 * X) := + dickson_two_one_eq_chebyshev_S R n ▸ (Chebyshev.S_comp_two_mul_X R n).symm /-- The `(m * n)`-th Dickson polynomial of the first kind is the composition of the `m`-th and `n`-th. -/ diff --git a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean index 924247aa7404b..a1e63fad9a328 100644 --- a/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean +++ b/Mathlib/RingTheory/Polynomial/Eisenstein/Basic.lean @@ -3,6 +3,7 @@ Copyright (c) 2022 Riccardo Brasca. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Riccardo Brasca -/ +import Mathlib.RingTheory.Adjoin.Basic import Mathlib.RingTheory.EisensteinCriterion import Mathlib.RingTheory.Polynomial.ScaleRoots @@ -62,7 +63,7 @@ theorem map (hf : f.IsWeaklyEisensteinAt 𝓟) {A : Type v} [CommRing A] (φ : R (f.map φ).IsWeaklyEisensteinAt (𝓟.map φ) := by 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 _ _))) + exact mem_map_of_mem _ (hf.mem (lt_of_lt_of_le hn natDegree_map_le)) end CommSemiring @@ -91,7 +92,7 @@ theorem exists_mem_adjoin_mul_eq_pow_natDegree {x : S} (hx : aeval x f = 0) (hmo congr · skip ext i - rw [coeff_map, hφ i.1 (lt_of_lt_of_le i.2 (natDegree_map_le _ _)), + rw [coeff_map, hφ i.1 (lt_of_lt_of_le i.2 natDegree_map_le), RingHom.map_mul, mul_assoc] rw [hx, ← mul_sum, neg_eq_neg_one_mul, ← mul_assoc (-1 : S), mul_comm (-1 : S), mul_assoc] refine diff --git a/Mathlib/RingTheory/Polynomial/GaussLemma.lean b/Mathlib/RingTheory/Polynomial/GaussLemma.lean index 5766fbc7a9398..3af13f8f046bd 100644 --- a/Mathlib/RingTheory/Polynomial/GaussLemma.lean +++ b/Mathlib/RingTheory/Polynomial/GaussLemma.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Aaron Anderson -/ import Mathlib.FieldTheory.SplittingField.Construction -import Mathlib.RingTheory.Int.Basic import Mathlib.RingTheory.Localization.Integral import Mathlib.RingTheory.IntegralClosure.IntegrallyClosed import Mathlib.RingTheory.Polynomial.Content diff --git a/Mathlib/RingTheory/Polynomial/HilbertPoly.lean b/Mathlib/RingTheory/Polynomial/HilbertPoly.lean new file mode 100644 index 0000000000000..66c5c57ec3060 --- /dev/null +++ b/Mathlib/RingTheory/Polynomial/HilbertPoly.lean @@ -0,0 +1,245 @@ +/- +Copyright (c) 2024 Fangming Li. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Fangming Li, Jujian Zhang +-/ +import Mathlib.Algebra.Polynomial.AlgebraMap +import Mathlib.Algebra.Polynomial.Eval.SMul +import Mathlib.Algebra.Polynomial.Roots +import Mathlib.Order.Interval.Set.Infinite +import Mathlib.RingTheory.Polynomial.Pochhammer +import Mathlib.RingTheory.PowerSeries.WellKnown +import Mathlib.Tactic.FieldSimp + +/-! +# Hilbert polynomials + +In this file, we formalise the following statement: if `F` is a field with characteristic `0`, then +given any `p : F[X]` and `d : ℕ`, there exists some `h : F[X]` such that for any large enough +`n : ℕ`, `h(n)` is equal to the coefficient of `Xⁿ` in the power series expansion of `p/(1 - X)ᵈ`. +This `h` is unique and is denoted as `Polynomial.hilbertPoly p d`. + +For example, given `d : ℕ`, the power series expansion of `1/(1-X)ᵈ⁺¹` in `F[X]` +is `Σₙ ((d + n).choose d)Xⁿ`, which equals `Σₙ ((n + 1)···(n + d)/d!)Xⁿ` and hence +`Polynomial.hilbertPoly (1 : F[X]) (d + 1)` is the polynomial `(X + 1)···(X + d)/d!`. Note that +if `d! = 0` in `F`, then the polynomial `(X + 1)···(X + d)/d!` no longer works, so we do not want +the characteristic of `F` to be divisible by `d!`. As `Polynomial.hilbertPoly` may take any +`p : F[X]` and `d : ℕ` as its inputs, it is necessary for us to assume that `CharZero F`. + +## Main definitions + +* `Polynomial.hilbertPoly p d`. Given a field `F`, a polynomial `p : F[X]` and a natural number `d`, + if `F` is of characteristic `0`, then `Polynomial.hilbertPoly p d : F[X]` is the polynomial whose + value at `n` equals the coefficient of `Xⁿ` in the power series expansion of `p/(1 - X)ᵈ`. + +## TODO + +* Hilbert polynomials of finitely generated graded modules over Noetherian rings. +-/ + +open Nat PowerSeries + +variable (F : Type*) [Field F] + +namespace Polynomial + +/-- +For any field `F` and natural numbers `d` and `k`, `Polynomial.preHilbertPoly F d k` +is defined as `(d.factorial : F)⁻¹ • ((ascPochhammer F d).comp (X - (C (k : F)) + 1))`. +This is the most basic form of Hilbert polynomials. `Polynomial.preHilbertPoly ℚ d 0` +is exactly the Hilbert polynomial of the polynomial ring `ℚ[X_0,...,X_d]` viewed as +a graded module over itself. In fact, `Polynomial.preHilbertPoly F d k` is the +same as `Polynomial.hilbertPoly ((X : F[X]) ^ k) (d + 1)` for any field `F` and +`d k : ℕ` (see the lemma `Polynomial.hilbertPoly_X_pow_succ`). See also the lemma +`Polynomial.preHilbertPoly_eq_choose_sub_add`, which states that if `CharZero F`, +then for any `d k n : ℕ` with `k ≤ n`, `(Polynomial.preHilbertPoly F d k).eval (n : F)` +equals `(n - k + d).choose d`. +-/ +noncomputable def preHilbertPoly (d k : ℕ) : F[X] := + (d.factorial : F)⁻¹ • ((ascPochhammer F d).comp (Polynomial.X - (C (k : F)) + 1)) + +lemma natDegree_preHilbertPoly [CharZero F] (d k : ℕ) : + (preHilbertPoly F d k).natDegree = d := by + have hne : (d ! : F) ≠ 0 := by norm_cast; positivity + rw [preHilbertPoly, natDegree_smul _ (inv_ne_zero hne), natDegree_comp, ascPochhammer_natDegree, + add_comm_sub, ← C_1, ← map_sub, natDegree_add_C, natDegree_X, mul_one] + +lemma coeff_preHilbertPoly_self [CharZero F] (d k : ℕ) : + (preHilbertPoly F d k).coeff d = (d ! : F)⁻¹ := by + delta preHilbertPoly + have hne : (d ! : F) ≠ 0 := by norm_cast; positivity + have heq : d = ((ascPochhammer F d).comp (X - C (k : F) + 1)).natDegree := + (natDegree_preHilbertPoly F d k).symm.trans (natDegree_smul _ (inv_ne_zero hne)) + nth_rw 3 [heq] + calc + _ = (d ! : F)⁻¹ • ((ascPochhammer F d).comp (X - C ((k : F) - 1))).leadingCoeff := by + simp only [sub_add, ← C_1, ← map_sub, coeff_smul, coeff_natDegree] + _ = (d ! : F)⁻¹ := by + simp only [leadingCoeff_comp (ne_of_eq_of_ne (natDegree_X_sub_C _) one_ne_zero), Monic.def.1 + (monic_ascPochhammer _ _), one_mul, leadingCoeff_X_sub_C, one_pow, smul_eq_mul, mul_one] + +lemma leadingCoeff_preHilbertPoly [CharZero F] (d k : ℕ) : + (preHilbertPoly F d k).leadingCoeff = (d ! : F)⁻¹ := by + rw [leadingCoeff, natDegree_preHilbertPoly, coeff_preHilbertPoly_self] + +lemma preHilbertPoly_eq_choose_sub_add [CharZero F] (d : ℕ) {k n : ℕ} (hkn : k ≤ n): + (preHilbertPoly F d k).eval (n : F) = (n - k + d).choose d := by + have : (d ! : F) ≠ 0 := by norm_cast; positivity + calc + _ = (↑d !)⁻¹ * eval (↑(n - k + 1)) (ascPochhammer F d) := by simp [cast_sub hkn, preHilbertPoly] + _ = (n - k + d).choose d := by + rw [ascPochhammer_nat_eq_natCast_ascFactorial]; + field_simp [ascFactorial_eq_factorial_mul_choose] + +variable {F} + +/-- +`Polynomial.hilbertPoly p 0 = 0`; for any `d : ℕ`, `Polynomial.hilbertPoly p (d + 1)` +is defined as `∑ i in p.support, (p.coeff i) • Polynomial.preHilbertPoly F d i`. If +`M` is a graded module whose Poincaré series can be written as `p(X)/(1 - X)ᵈ` for some +`p : ℚ[X]` with integer coefficients, then `Polynomial.hilbertPoly p d` is the Hilbert +polynomial of `M`. See also `Polynomial.coeff_mul_invOneSubPow_eq_hilbertPoly_eval`, +which says that `PowerSeries.coeff F n (p * PowerSeries.invOneSubPow F d)` equals +`(Polynomial.hilbertPoly p d).eval (n : F)` for any large enough `n : ℕ`. +-/ +noncomputable def hilbertPoly (p : F[X]) : (d : ℕ) → F[X] + | 0 => 0 + | d + 1 => ∑ i in p.support, (p.coeff i) • preHilbertPoly F d i + +variable (F) in +lemma hilbertPoly_zero_nat (d : ℕ) : hilbertPoly (0 : F[X]) d = 0 := by + delta hilbertPoly; induction d with + | zero => simp only + | succ d _ => simp only [coeff_zero, zero_smul, Finset.sum_const_zero] + +lemma hilbertPoly_poly_zero (p : F[X]) : hilbertPoly p 0 = 0 := rfl + +lemma hilbertPoly_poly_succ (p : F[X]) (d : ℕ) : + hilbertPoly p (d + 1) = ∑ i in p.support, (p.coeff i) • preHilbertPoly F d i := rfl + +variable (F) in +lemma hilbertPoly_X_pow_succ (d k : ℕ) : + hilbertPoly ((X : F[X]) ^ k) (d + 1) = preHilbertPoly F d k := by + delta hilbertPoly; simp + +variable [CharZero F] + +/-- +The key property of Hilbert polynomials. If `F` is a field with characteristic `0`, `p : F[X]` and +`d : ℕ`, then for any large enough `n : ℕ`, `(Polynomial.hilbertPoly p d).eval (n : F)` equals the +coefficient of `Xⁿ` in the power series expansion of `p/(1 - X)ᵈ`. +-/ +theorem coeff_mul_invOneSubPow_eq_hilbertPoly_eval + {p : F[X]} (d : ℕ) {n : ℕ} (hn : p.natDegree < n) : + PowerSeries.coeff F n (p * invOneSubPow F d) = (hilbertPoly p d).eval (n : F) := by + delta hilbertPoly; induction d with + | zero => simp only [invOneSubPow_zero, Units.val_one, mul_one, coeff_coe, eval_zero] + exact coeff_eq_zero_of_natDegree_lt hn + | succ d hd => + simp only [eval_finset_sum, eval_smul, smul_eq_mul] + rw [← Finset.sum_coe_sort] + have h_le (i : p.support) : (i : ℕ) ≤ n := + le_trans (le_natDegree_of_ne_zero <| mem_support_iff.1 i.2) hn.le + have h (i : p.support) : eval ↑n (preHilbertPoly F d ↑i) = (n + d - ↑i).choose d := by + rw [preHilbertPoly_eq_choose_sub_add _ _ (h_le i), Nat.sub_add_comm (h_le i)] + simp_rw [h] + rw [Finset.sum_coe_sort _ (fun x => (p.coeff ↑x) * (_ + d - ↑x).choose _), + PowerSeries.coeff_mul, Finset.Nat.sum_antidiagonal_eq_sum_range_succ_mk, + invOneSubPow_val_eq_mk_sub_one_add_choose_of_pos _ _ (zero_lt_succ d)] + simp only [coeff_coe, coeff_mk] + symm + refine Finset.sum_subset_zero_on_sdiff (fun s hs ↦ ?_) (fun x hx ↦ ?_) (fun x hx ↦ ?_) + · rw [Finset.mem_range_succ_iff] + exact h_le ⟨s, hs⟩ + · simp only [Finset.mem_sdiff, mem_support_iff, not_not] at hx + rw [hx.2, zero_mul] + · rw [add_comm, Nat.add_sub_assoc (h_le ⟨x, hx⟩), succ_eq_add_one, add_tsub_cancel_right] + +/-- +The polynomial satisfying the key property of `Polynomial.hilbertPoly p d` is unique. +-/ +theorem exists_unique_hilbertPoly (p : F[X]) (d : ℕ) : + ∃! h : F[X], ∃ N : ℕ, ∀ n > N, + PowerSeries.coeff F n (p * invOneSubPow F d) = h.eval (n : F) := by + use hilbertPoly p d; constructor + · use p.natDegree + exact fun n => coeff_mul_invOneSubPow_eq_hilbertPoly_eval d + · rintro h ⟨N, hhN⟩ + apply eq_of_infinite_eval_eq h (hilbertPoly p d) + apply ((Set.Ioi_infinite (max N p.natDegree)).image cast_injective.injOn).mono + rintro x ⟨n, hn, rfl⟩ + simp only [Set.mem_Ioi, sup_lt_iff, Set.mem_setOf_eq] at hn ⊢ + rw [← coeff_mul_invOneSubPow_eq_hilbertPoly_eval d hn.2, hhN n hn.1] + +/-- +If `h : F[X]` and there exists some `N : ℕ` such that for any number `n : ℕ` bigger than `N` +we have `PowerSeries.coeff F n (p * invOneSubPow F d) = h.eval (n : F)`, then `h` is exactly +`Polynomial.hilbertPoly p d`. +-/ +theorem eq_hilbertPoly_of_forall_coeff_eq_eval + {p h : F[X]} {d : ℕ} (N : ℕ) (hhN : ∀ n > N, + PowerSeries.coeff F n (p * invOneSubPow F d) = h.eval (n : F)) : + h = hilbertPoly p d := + ExistsUnique.unique (exists_unique_hilbertPoly p d) ⟨N, hhN⟩ + ⟨p.natDegree, fun _ x => coeff_mul_invOneSubPow_eq_hilbertPoly_eval d x⟩ + +lemma hilbertPoly_mul_one_sub_succ (p : F[X]) (d : ℕ) : + hilbertPoly (p * (1 - X)) (d + 1) = hilbertPoly p d := by + apply eq_hilbertPoly_of_forall_coeff_eq_eval (p * (1 - X)).natDegree + intro n hn + have heq : 1 - PowerSeries.X = ((1 - X : F[X]) : F⟦X⟧) := by simp only [coe_sub, coe_one, coe_X] + rw [← one_sub_pow_mul_invOneSubPow_val_add_eq_invOneSubPow_val F d 1, pow_one, ← mul_assoc, heq, + ← coe_mul, coeff_mul_invOneSubPow_eq_hilbertPoly_eval (d + 1) hn] + +lemma hilbertPoly_mul_one_sub_pow_add (p : F[X]) (d e : ℕ) : + hilbertPoly (p * (1 - X) ^ e) (d + e) = hilbertPoly p d := by + induction e with + | zero => simp + | succ e he => rw [pow_add, pow_one, ← mul_assoc, ← add_assoc, hilbertPoly_mul_one_sub_succ, he] + +lemma hilbertPoly_eq_zero_of_le_rootMultiplicity_one + {p : F[X]} {d : ℕ} (hdp : d ≤ p.rootMultiplicity 1) : + hilbertPoly p d = 0 := by + by_cases hp : p = 0 + · rw [hp, hilbertPoly_zero_nat] + · rcases exists_eq_pow_rootMultiplicity_mul_and_not_dvd p hp 1 with ⟨q, hq1, hq2⟩ + have heq : p = q * (- 1) ^ p.rootMultiplicity 1 * (1 - X) ^ p.rootMultiplicity 1 := by + simp only [mul_assoc, ← mul_pow, neg_mul, one_mul, neg_sub] + exact hq1.trans (mul_comm _ _) + rw [heq, ← zero_add d, ← Nat.sub_add_cancel hdp, pow_add (1 - X), ← mul_assoc, + hilbertPoly_mul_one_sub_pow_add, hilbertPoly] + +theorem natDegree_hilbertPoly_of_ne_zero_of_rootMultiplicity_lt + {p : F[X]} {d : ℕ} (hp : p ≠ 0) (hpd : p.rootMultiplicity 1 < d) : + (hilbertPoly p d).natDegree = d - p.rootMultiplicity 1 - 1 := by + rcases exists_eq_pow_rootMultiplicity_mul_and_not_dvd p hp 1 with ⟨q, hq1, hq2⟩ + have heq : p = q * (- 1) ^ p.rootMultiplicity 1 * (1 - X) ^ p.rootMultiplicity 1 := by + simp only [mul_assoc, ← mul_pow, neg_mul, one_mul, neg_sub] + exact hq1.trans (mul_comm _ _) + nth_rw 1 [heq, ← Nat.sub_add_cancel (le_of_lt hpd), hilbertPoly_mul_one_sub_pow_add, + ← Nat.sub_add_cancel (Nat.le_sub_of_add_le' <| add_one_le_of_lt hpd)] + delta hilbertPoly + apply natDegree_eq_of_le_of_coeff_ne_zero + · apply natDegree_sum_le_of_forall_le _ _ <| fun _ _ => ?_ + apply le_trans (natDegree_smul_le _ _) + rw [natDegree_preHilbertPoly] + · have : (fun (x : ℕ) (a : F) => a) = fun x a => a * 1 ^ x := by simp only [one_pow, mul_one] + simp only [finset_sum_coeff, coeff_smul, smul_eq_mul, coeff_preHilbertPoly_self, + ← Finset.sum_mul, ← sum_def _ (fun _ a => a), this, ← eval_eq_sum, eval_mul, eval_pow, + eval_neg, eval_one, _root_.mul_eq_zero, pow_eq_zero_iff', neg_eq_zero, one_ne_zero, ne_eq, + false_and, or_false, inv_eq_zero, cast_eq_zero, not_or] + exact ⟨(not_iff_not.2 dvd_iff_isRoot).1 hq2, factorial_ne_zero _⟩ + +theorem natDegree_hilbertPoly_of_ne_zero + {p : F[X]} {d : ℕ} (hh : hilbertPoly p d ≠ 0) : + (hilbertPoly p d).natDegree = d - p.rootMultiplicity 1 - 1 := by + have hp : p ≠ 0 := by + intro h + rw [h] at hh + exact hh (hilbertPoly_zero_nat F d) + have hpd : p.rootMultiplicity 1 < d := by + by_contra h + exact hh (hilbertPoly_eq_zero_of_le_rootMultiplicity_one <| not_lt.1 h) + exact natDegree_hilbertPoly_of_ne_zero_of_rootMultiplicity_lt hp hpd + +end Polynomial diff --git a/Mathlib/RingTheory/Polynomial/Ideal.lean b/Mathlib/RingTheory/Polynomial/Ideal.lean new file mode 100644 index 0000000000000..e6fd7043addce --- /dev/null +++ b/Mathlib/RingTheory/Polynomial/Ideal.lean @@ -0,0 +1,76 @@ +/- +Copyright (c) 2019 Kenny Lau. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Kenny Lau +-/ +import Mathlib.Algebra.Polynomial.RingDivision +import Mathlib.RingTheory.Adjoin.Polynomial +import Mathlib.RingTheory.Ideal.Maps + +/-! +# Ideals in polynomial rings +-/ + +noncomputable section + +open Polynomial + +open Finset + +universe u v w + +namespace Polynomial + +variable {R : Type*} [CommRing R] {a : R} + +theorem mem_span_C_X_sub_C_X_sub_C_iff_eval_eval_eq_zero {b : R[X]} {P : R[X][X]} : + P ∈ Ideal.span {C (X - C a), X - C b} ↔ (P.eval b).eval a = 0 := by + rw [Ideal.mem_span_pair] + constructor <;> intro h + · rcases h with ⟨_, _, rfl⟩ + simp only [eval_C, eval_X, eval_add, eval_sub, eval_mul, add_zero, mul_zero, sub_self] + · rcases dvd_iff_isRoot.mpr h with ⟨p, hp⟩ + rcases @X_sub_C_dvd_sub_C_eval _ b _ P with ⟨q, hq⟩ + exact ⟨C p, q, by rw [mul_comm, mul_comm q, eq_add_of_sub_eq' hq, hp, C_mul]⟩ + +theorem ker_evalRingHom (x : R) : RingHom.ker (evalRingHom x) = Ideal.span {X - C x} := by + ext y + simp [Ideal.mem_span_singleton, dvd_iff_isRoot, RingHom.mem_ker] + +@[simp] +theorem ker_modByMonicHom {q : R[X]} (hq : q.Monic) : + LinearMap.ker (Polynomial.modByMonicHom q) = (Ideal.span {q}).restrictScalars R := + Submodule.ext fun _ => (mem_ker_modByMonic hq).trans Ideal.mem_span_singleton.symm + +open Algebra in +lemma _root_.Algebra.mem_ideal_map_adjoin {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] + (x : S) (I : Ideal R) {y : adjoin R ({x} : Set S)} : + y ∈ I.map (algebraMap R (adjoin R ({x} : Set S))) ↔ + ∃ p : R[X], (∀ i, p.coeff i ∈ I) ∧ Polynomial.aeval x p = y := by + constructor + · intro H + induction' H using Submodule.span_induction with a ha a b ha hb ha' hb' a b hb hb' + · obtain ⟨a, ha, rfl⟩ := ha + exact ⟨C a, fun i ↦ by rw [coeff_C]; aesop, aeval_C _ _⟩ + · exact ⟨0, by simp, aeval_zero _⟩ + · obtain ⟨a, ha, ha'⟩ := ha' + obtain ⟨b, hb, hb'⟩ := hb' + exact ⟨a + b, fun i ↦ by simpa using add_mem (ha i) (hb i), by simp [ha', hb']⟩ + · obtain ⟨b', hb, hb'⟩ := hb' + obtain ⟨a, ha⟩ := a + rw [Algebra.adjoin_singleton_eq_range_aeval] at ha + obtain ⟨p, hp : aeval x p = a⟩ := ha + refine ⟨p * b', fun i ↦ ?_, by simp [hp, hb']⟩ + rw [coeff_mul] + exact sum_mem fun i hi ↦ Ideal.mul_mem_left _ _ (hb _) + · rintro ⟨p, hp, hp'⟩ + have : y = ∑ i in p.support, p.coeff i • ⟨_, (X ^ i).aeval_mem_adjoin_singleton _ x⟩ := by + trans ∑ i in p.support, ⟨_, (C (p.coeff i) * X ^ i).aeval_mem_adjoin_singleton _ x⟩ + · ext1 + simp only [AddSubmonoidClass.coe_finset_sum, ← map_sum, ← hp', ← as_sum_support_C_mul_X_pow] + · congr with i + simp [Algebra.smul_def] + simp_rw [this, Algebra.smul_def] + exact sum_mem fun i _ ↦ Ideal.mul_mem_right _ _ (Ideal.mem_map_of_mem _ (hp i)) + +end Polynomial diff --git a/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean index 75da4b3b8edc2..ee4f04ec120b8 100644 --- a/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean +++ b/Mathlib/RingTheory/Polynomial/IntegralNormalization.lean @@ -1,11 +1,10 @@ /- Copyright (c) 2018 Chris Hughes. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker +Authors: Chris Hughes, Johannes Hölzl, Kim Morrison, Jens Wagemaker, Andrew Yang, Yuyang Zhao -/ -import Mathlib.Algebra.Polynomial.AlgebraMap -import Mathlib.Algebra.Polynomial.Degree.Lemmas import Mathlib.Algebra.Polynomial.Monic +import Mathlib.RingTheory.Polynomial.ScaleRoots /-! # Theory of monic polynomials @@ -28,115 +27,158 @@ section Semiring variable [Semiring R] -/-- If `f : R[X]` is a nonzero polynomial with root `z`, `integralNormalization f` is +/-- If `p : R[X]` is a nonzero polynomial with root `z`, `integralNormalization p` is a monic polynomial with root `leadingCoeff f * z`. Moreover, `integralNormalization 0 = 0`. -/ -noncomputable def integralNormalization (f : R[X]) : R[X] := - ∑ i ∈ f.support, - monomial i (if f.degree = i then 1 else coeff f i * f.leadingCoeff ^ (f.natDegree - 1 - i)) +noncomputable def integralNormalization (p : R[X]) : R[X] := + p.sum fun i a ↦ + monomial i (if p.degree = i then 1 else a * p.leadingCoeff ^ (p.natDegree - 1 - i)) @[simp] theorem integralNormalization_zero : integralNormalization (0 : R[X]) = 0 := by simp [integralNormalization] -theorem integralNormalization_coeff {f : R[X]} {i : ℕ} : - (integralNormalization f).coeff i = - if f.degree = i then 1 else coeff f i * f.leadingCoeff ^ (f.natDegree - 1 - i) := by - have : f.coeff i = 0 → f.degree ≠ i := fun hc hd => coeff_ne_zero_of_eq_degree hd hc - simp +contextual [integralNormalization, coeff_monomial, this, +@[simp] +theorem integralNormalization_C {x : R} (hx : x ≠ 0) : integralNormalization (C x) = 1 := by + simp [integralNormalization, sum_def, support_C hx, degree_C hx] + +variable {p : R[X]} + +theorem integralNormalization_coeff {i : ℕ} : + (integralNormalization p).coeff i = + if p.degree = i then 1 else coeff p i * p.leadingCoeff ^ (p.natDegree - 1 - i) := by + have : p.coeff i = 0 → p.degree ≠ i := fun hc hd => coeff_ne_zero_of_eq_degree hd hc + simp +contextual [sum_def, integralNormalization, coeff_monomial, this, mem_support_iff] -theorem integralNormalization_support {f : R[X]} : - (integralNormalization f).support ⊆ f.support := by +theorem support_integralNormalization_subset : + (integralNormalization p).support ⊆ p.support := by intro - simp +contextual [integralNormalization, coeff_monomial, mem_support_iff] + simp +contextual [sum_def, integralNormalization, coeff_monomial, mem_support_iff] + +@[deprecated (since := "2024-11-30")] +alias integralNormalization_support := support_integralNormalization_subset -theorem integralNormalization_coeff_degree {f : R[X]} {i : ℕ} (hi : f.degree = i) : - (integralNormalization f).coeff i = 1 := by rw [integralNormalization_coeff, if_pos hi] +theorem integralNormalization_coeff_degree {i : ℕ} (hi : p.degree = i) : + (integralNormalization p).coeff i = 1 := by rw [integralNormalization_coeff, if_pos hi] -theorem integralNormalization_coeff_natDegree {f : R[X]} (hf : f ≠ 0) : - (integralNormalization f).coeff (natDegree f) = 1 := - integralNormalization_coeff_degree (degree_eq_natDegree hf) +theorem integralNormalization_coeff_natDegree (hp : p ≠ 0) : + (integralNormalization p).coeff (natDegree p) = 1 := + integralNormalization_coeff_degree (degree_eq_natDegree hp) -theorem integralNormalization_coeff_ne_degree {f : R[X]} {i : ℕ} (hi : f.degree ≠ i) : - coeff (integralNormalization f) i = coeff f i * f.leadingCoeff ^ (f.natDegree - 1 - i) := by +theorem integralNormalization_coeff_degree_ne {i : ℕ} (hi : p.degree ≠ i) : + coeff (integralNormalization p) i = coeff p i * p.leadingCoeff ^ (p.natDegree - 1 - i) := by rw [integralNormalization_coeff, if_neg hi] -theorem integralNormalization_coeff_ne_natDegree {f : R[X]} {i : ℕ} (hi : i ≠ natDegree f) : - coeff (integralNormalization f) i = coeff f i * f.leadingCoeff ^ (f.natDegree - 1 - i) := - integralNormalization_coeff_ne_degree (degree_ne_of_natDegree_ne hi.symm) +theorem integralNormalization_coeff_ne_natDegree {i : ℕ} (hi : i ≠ natDegree p) : + coeff (integralNormalization p) i = coeff p i * p.leadingCoeff ^ (p.natDegree - 1 - i) := + integralNormalization_coeff_degree_ne (degree_ne_of_natDegree_ne hi.symm) -theorem monic_integralNormalization {f : R[X]} (hf : f ≠ 0) : Monic (integralNormalization f) := - monic_of_degree_le f.natDegree +theorem monic_integralNormalization (hp : p ≠ 0) : Monic (integralNormalization p) := + monic_of_degree_le p.natDegree (Finset.sup_le fun i h => - WithBot.coe_le_coe.2 <| le_natDegree_of_mem_supp i <| integralNormalization_support h) - (integralNormalization_coeff_natDegree hf) + WithBot.coe_le_coe.2 <| le_natDegree_of_mem_supp i <| support_integralNormalization_subset h) + (integralNormalization_coeff_natDegree hp) + +theorem integralNormalization_coeff_mul_leadingCoeff_pow (i : ℕ) (hp : 1 ≤ natDegree p) : + (integralNormalization p).coeff i * p.leadingCoeff ^ i = + p.coeff i * p.leadingCoeff ^ (p.natDegree - 1) := by + rw [integralNormalization_coeff] + split_ifs with h + · simp [natDegree_eq_of_degree_eq_some h, leadingCoeff, + ← pow_succ', tsub_add_cancel_of_le (natDegree_eq_of_degree_eq_some h ▸ hp)] + · simp only [mul_assoc, ← pow_add] + by_cases h' : i < p.degree + · rw [tsub_add_cancel_of_le] + rw [le_tsub_iff_right hp, Nat.succ_le_iff] + exact coe_lt_degree.mp h' + · simp [coeff_eq_zero_of_degree_lt (lt_of_le_of_ne (le_of_not_gt h') h)] + +theorem integralNormalization_mul_C_leadingCoeff (p : R[X]) : + integralNormalization p * C p.leadingCoeff = scaleRoots p p.leadingCoeff := by + ext i + rw [coeff_mul_C, integralNormalization_coeff] + split_ifs with h + · simp [natDegree_eq_of_degree_eq_some h, leadingCoeff] + · simp only [ge_iff_le, tsub_le_iff_right, smul_eq_mul, coeff_scaleRoots] + by_cases h' : i < p.degree + · rw [mul_assoc, ← pow_succ, tsub_right_comm, tsub_add_cancel_of_le] + rw [le_tsub_iff_left (coe_lt_degree.mp h').le, Nat.succ_le_iff] + exact coe_lt_degree.mp h' + · simp [coeff_eq_zero_of_degree_lt (lt_of_le_of_ne (le_of_not_gt h') h)] + +theorem integralNormalization_degree : (integralNormalization p).degree = p.degree := by + apply le_antisymm + · exact Finset.sup_mono p.support_integralNormalization_subset + · rw [← degree_scaleRoots, ← integralNormalization_mul_C_leadingCoeff] + exact (degree_mul_le _ _).trans (add_le_of_nonpos_right degree_C_le) + +variable {A : Type*} [CommSemiring S] [Semiring A] + +theorem leadingCoeff_smul_integralNormalization (p : S[X]) : + p.leadingCoeff • integralNormalization p = scaleRoots p p.leadingCoeff := by + rw [Algebra.smul_def, algebraMap_eq, mul_comm, integralNormalization_mul_C_leadingCoeff] + +theorem integralNormalization_eval₂_leadingCoeff_mul_of_commute (h : 1 ≤ p.natDegree) (f : R →+* A) + (x : A) (h₁ : Commute (f p.leadingCoeff) x) (h₂ : ∀ {r r'}, Commute (f r) (f r')) : + (integralNormalization p).eval₂ f (f p.leadingCoeff * x) = + f p.leadingCoeff ^ (p.natDegree - 1) * p.eval₂ f x := by + rw [eval₂_eq_sum_range, eval₂_eq_sum_range, Finset.mul_sum] + apply Finset.sum_congr + · rw [natDegree_eq_of_degree_eq p.integralNormalization_degree] + intro n _hn + rw [h₁.mul_pow, ← mul_assoc, ← f.map_pow, ← f.map_mul, + integralNormalization_coeff_mul_leadingCoeff_pow _ h, f.map_mul, h₂.eq, f.map_pow, mul_assoc] + +theorem integralNormalization_eval₂_leadingCoeff_mul (h : 1 ≤ p.natDegree) (f : R →+* S) (x : S) : + (integralNormalization p).eval₂ f (f p.leadingCoeff * x) = + f p.leadingCoeff ^ (p.natDegree - 1) * p.eval₂ f x := + integralNormalization_eval₂_leadingCoeff_mul_of_commute h _ _ (.all _ _) (.all _ _) + +theorem integralNormalization_eval₂_eq_zero_of_commute {p : R[X]} (f : R →+* A) {z : A} + (hz : eval₂ f z p = 0) (h₁ : Commute (f p.leadingCoeff) z) (h₂ : ∀ {r r'}, Commute (f r) (f r')) + (inj : ∀ x : R, f x = 0 → x = 0) : + eval₂ f (f p.leadingCoeff * z) (integralNormalization p) = 0 := by + obtain (h | h) := p.natDegree.eq_zero_or_pos + · by_cases h0 : coeff p 0 = 0 + · rw [eq_C_of_natDegree_eq_zero h] + simp [h0] + · rw [eq_C_of_natDegree_eq_zero h, eval₂_C] at hz + exact absurd (inj _ hz) h0 + · rw [integralNormalization_eval₂_leadingCoeff_mul_of_commute h _ _ h₁ h₂, hz, mul_zero] + +theorem integralNormalization_eval₂_eq_zero {p : R[X]} (f : R →+* S) {z : S} (hz : eval₂ f z p = 0) + (inj : ∀ x : R, f x = 0 → x = 0) : + eval₂ f (f p.leadingCoeff * z) (integralNormalization p) = 0 := + integralNormalization_eval₂_eq_zero_of_commute _ hz (.all _ _) (.all _ _) inj + +theorem integralNormalization_aeval_eq_zero [Algebra S A] {f : S[X]} {z : A} (hz : aeval z f = 0) + (inj : ∀ x : S, algebraMap S A x = 0 → x = 0) : + aeval (algebraMap S A f.leadingCoeff * z) (integralNormalization f) = 0 := + integralNormalization_eval₂_eq_zero_of_commute (algebraMap S A) hz + (Algebra.commute_algebraMap_left _ _) (.map (.all _ _) _) inj end Semiring -section IsDomain +section IsCancelMulZero -variable [Ring R] [IsDomain R] +variable [Semiring R] [IsCancelMulZero R] @[simp] theorem support_integralNormalization {f : R[X]} : (integralNormalization f).support = f.support := by + nontriviality R using Subsingleton.eq_zero + have : IsDomain R := {} by_cases hf : f = 0; · simp [hf] ext i - refine ⟨fun h => integralNormalization_support h, ?_⟩ + refine ⟨fun h => support_integralNormalization_subset h, ?_⟩ simp only [integralNormalization_coeff, mem_support_iff] intro hfi split_ifs with hi <;> simp [hf, hfi, hi] -end IsDomain - -section IsDomain - -variable [CommRing R] [IsDomain R] -variable [CommSemiring S] - -theorem integralNormalization_eval₂_eq_zero {p : R[X]} (f : R →+* S) {z : S} (hz : eval₂ f z p = 0) - (inj : ∀ x : R, f x = 0 → x = 0) : - eval₂ f (z * f p.leadingCoeff) (integralNormalization p) = 0 := - calc - eval₂ f (z * f p.leadingCoeff) (integralNormalization p) = - p.support.attach.sum fun i => - 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] - rw [← Finset.sum_attach] - _ = - p.support.attach.sum fun i => - f (coeff p i.1 * p.leadingCoeff ^ (natDegree p - 1)) * z ^ i.1 := by - by_cases hp : p = 0; · simp [hp] - have one_le_deg : 1 ≤ natDegree p := - Nat.succ_le_of_lt (natDegree_pos_of_eval₂_root hp f hz inj) - congr with i - congr 2 - by_cases hi : i.1 = natDegree p - · rw [hi, integralNormalization_coeff_degree, one_mul, leadingCoeff, ← pow_succ', - tsub_add_cancel_of_le one_le_deg] - exact degree_eq_natDegree hp - · have : i.1 ≤ p.natDegree - 1 := - Nat.le_sub_one_of_lt - (lt_of_le_of_ne (le_natDegree_of_ne_zero (mem_support_iff.mp i.2)) hi) - rw [integralNormalization_coeff_ne_natDegree hi, mul_assoc, ← pow_add, - tsub_add_cancel_of_le this] - _ = f p.leadingCoeff ^ (natDegree p - 1) * eval₂ f z p := by - 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 p.support.sum_attach fun i ↦ f (p.coeff i) * z ^ i - _ = 0 := by rw [hz, mul_zero] - -theorem integralNormalization_aeval_eq_zero [Algebra R S] {f : R[X]} {z : S} (hz : aeval z f = 0) - (inj : ∀ x : R, algebraMap R S x = 0 → x = 0) : - aeval (z * algebraMap R S f.leadingCoeff) (integralNormalization f) = 0 := - integralNormalization_eval₂_eq_zero (algebraMap R S) hz inj - -end IsDomain +end IsCancelMulZero end IntegralNormalization diff --git a/Mathlib/RingTheory/Polynomial/Pochhammer.lean b/Mathlib/RingTheory/Polynomial/Pochhammer.lean index d6872afb27cbc..29176297e9018 100644 --- a/Mathlib/RingTheory/Polynomial/Pochhammer.lean +++ b/Mathlib/RingTheory/Polynomial/Pochhammer.lean @@ -153,10 +153,20 @@ theorem ascPochhammer_nat_eq_ascFactorial (n : ℕ) : rw [ascPochhammer_succ_right, eval_mul, ascPochhammer_nat_eq_ascFactorial n t, eval_add, eval_X, eval_natCast, Nat.cast_id, Nat.ascFactorial_succ, mul_comm] +theorem ascPochhammer_nat_eq_natCast_ascFactorial (S : Type*) [Semiring S] (n k : ℕ) : + (ascPochhammer S k).eval (n : S) = n.ascFactorial k := by + norm_cast + rw [ascPochhammer_nat_eq_ascFactorial] + theorem ascPochhammer_nat_eq_descFactorial (a b : ℕ) : (ascPochhammer ℕ b).eval a = (a + b - 1).descFactorial b := by rw [ascPochhammer_nat_eq_ascFactorial, Nat.add_descFactorial_eq_ascFactorial'] +theorem ascPochhammer_nat_eq_natCast_descFactorial (S : Type*) [Semiring S] (a b : ℕ) : + (ascPochhammer S b).eval (a : S) = (a + b - 1).descFactorial b := by + norm_cast + rw [ascPochhammer_nat_eq_descFactorial] + @[simp] theorem ascPochhammer_natDegree (n : ℕ) [NoZeroDivisors S] [Nontrivial S] : (ascPochhammer S n).natDegree = n := by diff --git a/Mathlib/RingTheory/Polynomial/Quotient.lean b/Mathlib/RingTheory/Polynomial/Quotient.lean index 96efc3704a697..ec63a3a57ca23 100644 --- a/Mathlib/RingTheory/Polynomial/Quotient.lean +++ b/Mathlib/RingTheory/Polynomial/Quotient.lean @@ -8,6 +8,7 @@ import Mathlib.Algebra.Polynomial.Eval.SMul import Mathlib.GroupTheory.GroupAction.Ring import Mathlib.RingTheory.Ideal.Quotient.Operations import Mathlib.RingTheory.Polynomial.Basic +import Mathlib.RingTheory.Polynomial.Ideal /-! # Quotients of polynomial rings diff --git a/Mathlib/RingTheory/Polynomial/Tower.lean b/Mathlib/RingTheory/Polynomial/Tower.lean index 5e49599ddbda9..3177903b37969 100644 --- a/Mathlib/RingTheory/Polynomial/Tower.lean +++ b/Mathlib/RingTheory/Polynomial/Tower.lean @@ -36,9 +36,9 @@ theorem aeval_map_algebraMap (x : B) (p : R[X]) : aeval x (map (algebraMap R A) rw [aeval_def, aeval_def, eval₂_map, IsScalarTower.algebraMap_eq R A B] @[simp] -lemma eval_map_algebraMap (P : R[X]) (a : A) : - (map (algebraMap R A) P).eval a = aeval a P := by - rw [← aeval_map_algebraMap (A := A), coe_aeval_eq_eval] +lemma eval_map_algebraMap (P : R[X]) (b : B) : + (map (algebraMap R B) P).eval b = aeval b P := by + rw [aeval_def, eval_map] end Semiring diff --git a/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean b/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean index 6e24a23d71aee..7d5e251cc6781 100644 --- a/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean +++ b/Mathlib/RingTheory/Polynomial/UniqueFactorization.lean @@ -128,7 +128,7 @@ instance (priority := 100) uniqueFactorizationMonoid : exact ⟨w.map (rename (↑)), fun b hb => let ⟨b', hb', he⟩ := Multiset.mem_map.1 hb - he ▸ (prime_rename_iff ↑s).2 (h b' hb'), + he ▸ (prime_rename_iff (σ := σ) ↑s).2 (h b' hb'), Units.map (@rename s σ D _ (↑)).toRingHom.toMonoidHom u, by erw [Multiset.prod_hom, ← map_mul, hw]⟩ diff --git a/Mathlib/RingTheory/PowerBasis.lean b/Mathlib/RingTheory/PowerBasis.lean index a6ef6f783cb75..1e67541ed7447 100644 --- a/Mathlib/RingTheory/PowerBasis.lean +++ b/Mathlib/RingTheory/PowerBasis.lean @@ -5,6 +5,7 @@ Authors: Anne Baanen -/ import Mathlib.FieldTheory.Minpoly.Field import Mathlib.LinearAlgebra.SModEq +import Mathlib.RingTheory.Ideal.BigOperators /-! # Power basis diff --git a/Mathlib/RingTheory/PowerSeries/Basic.lean b/Mathlib/RingTheory/PowerSeries/Basic.lean index 85884f5a24154..2d18bb322885f 100644 --- a/Mathlib/RingTheory/PowerSeries/Basic.lean +++ b/Mathlib/RingTheory/PowerSeries/Basic.lean @@ -155,6 +155,10 @@ theorem ext {φ ψ : R⟦X⟧} (h : ∀ n, coeff R n φ = coeff R n ψ) : φ = · apply h rfl +@[simp] +theorem forall_coeff_eq_zero (φ : R⟦X⟧) : (∀ n, coeff R n φ = 0) ↔ φ = 0 := + ⟨fun h => ext h, fun h => by simp [h]⟩ + /-- Two formal power series are equal if all their coefficients are equal. -/ add_decl_doc PowerSeries.ext_iff diff --git a/Mathlib/RingTheory/PowerSeries/Inverse.lean b/Mathlib/RingTheory/PowerSeries/Inverse.lean index f69014616a2de..419143bde5cd0 100644 --- a/Mathlib/RingTheory/PowerSeries/Inverse.lean +++ b/Mathlib/RingTheory/PowerSeries/Inverse.lean @@ -202,7 +202,7 @@ theorem smul_inv (r : k) (φ : k⟦X⟧) : (r • φ)⁻¹ = r⁻¹ • φ⁻¹ /-- `firstUnitCoeff` is the non-zero coefficient whose index is `f.order`, seen as a unit of the field. It is obtained using `divided_by_X_pow_order`, defined in `PowerSeries.Order`-/ def firstUnitCoeff {f : k⟦X⟧} (hf : f ≠ 0) : kˣ := - let d := f.order.get (order_finite_iff_ne_zero.mpr hf) + let d := f.order.lift (order_finite_iff_ne_zero.mpr hf) have f_const : coeff k d f ≠ 0 := by apply coeff_order have : Invertible (constantCoeff k (divided_by_X_pow_order hf)) := by apply invertibleOfNonzero @@ -258,8 +258,8 @@ theorem Unit_of_divided_by_X_pow_order_zero : Unit_of_divided_by_X_pow_order (0 theorem eq_divided_by_X_pow_order_Iff_Unit {f : k⟦X⟧} (hf : f ≠ 0) : f = divided_by_X_pow_order hf ↔ IsUnit f := ⟨fun h ↦ by rw [h]; exact isUnit_divided_by_X_pow_order hf, fun h ↦ by - have : f.order.get (order_finite_iff_ne_zero.mpr hf) = 0 := by - simp only [order_zero_of_unit h, PartENat.get_zero] + have : f.order.lift (order_finite_iff_ne_zero.mpr hf) = 0 := by + simp [order_zero_of_unit h] convert (self_eq_X_pow_order_mul_divided_by_X_pow_order hf).symm simp only [this, pow_zero, one_mul]⟩ @@ -295,7 +295,7 @@ theorem hasUnitMulPowIrreducibleFactorization : ⟨X, And.intro X_irreducible (by intro f hf - use f.order.get (order_finite_iff_ne_zero.mpr hf) + use f.order.lift (order_finite_iff_ne_zero.mpr hf) use Unit_of_divided_by_X_pow_order f simp only [Unit_of_divided_by_X_pow_order_nonzero hf] exact self_eq_X_pow_order_mul_divided_by_X_pow_order hf)⟩ diff --git a/Mathlib/RingTheory/PowerSeries/Order.lean b/Mathlib/RingTheory/PowerSeries/Order.lean index d428546cd604a..97eaca3724e77 100644 --- a/Mathlib/RingTheory/PowerSeries/Order.lean +++ b/Mathlib/RingTheory/PowerSeries/Order.lean @@ -7,7 +7,6 @@ Authors: Johan Commelin, Kenny Lau import Mathlib.Algebra.CharP.Defs import Mathlib.RingTheory.Multiplicity import Mathlib.RingTheory.PowerSeries.Basic -import Mathlib.Data.Nat.PartENat /-! # Formal power series (in one variable) - Order @@ -39,19 +38,16 @@ variable {R : Type*} section OrderBasic -open multiplicity - variable [Semiring R] {φ : R⟦X⟧} theorem exists_coeff_ne_zero_iff_ne_zero : (∃ n : ℕ, coeff R n φ ≠ 0) ↔ φ ≠ 0 := by refine not_iff_not.mp ?_ push_neg - -- FIXME: the `FunLike.coe` doesn't seem to be picked up in the expression after https://github.com/leanprover-community/mathlib4/pull/8386? - simp [PowerSeries.ext_iff, (coeff R _).map_zero] + simp [(coeff R _).map_zero] /-- The order of a formal power series `φ` is the greatest `n : PartENat` such that `X^n` divides `φ`. The order is `⊤` if and only if `φ = 0`. -/ -def order (φ : R⟦X⟧) : PartENat := +def order (φ : R⟦X⟧) : ℕ∞ := letI := Classical.decEq R letI := Classical.decEq R⟦X⟧ if h : φ = 0 then ⊤ else Nat.find (exists_coeff_ne_zero_iff_ne_zero.mpr h) @@ -61,20 +57,20 @@ def order (φ : R⟦X⟧) : PartENat := theorem order_zero : order (0 : R⟦X⟧) = ⊤ := dif_pos rfl -theorem order_finite_iff_ne_zero : (order φ).Dom ↔ φ ≠ 0 := by +theorem order_finite_iff_ne_zero : (order φ < ⊤) ↔ φ ≠ 0 := by simp only [order] constructor · split_ifs with h <;> intro H - · simp only [PartENat.top_eq_none, Part.not_none_dom] at H + · simp at H · exact h · intro h simp [h] /-- If the order of a formal power series is finite, then the coefficient indexed by the order is nonzero. -/ -theorem coeff_order (h : (order φ).Dom) : coeff R (φ.order.get h) φ ≠ 0 := by +theorem coeff_order (h : order φ < ⊤) : coeff R (φ.order.lift h) φ ≠ 0 := by classical - simp only [order, order_finite_iff_ne_zero.mp h, not_false_iff, dif_neg, PartENat.get_natCast'] + simp only [order, order_finite_iff_ne_zero.mp h, not_false_iff, dif_neg] generalize_proofs h exact Nat.find_spec h @@ -83,8 +79,7 @@ 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 rw [order, dif_neg] - · simp only [PartENat.coe_le_coe] - exact Nat.find_le h + · simpa using ⟨n, le_rfl, h⟩ · exact exists_coeff_ne_zero_iff_ne_zero.mp ⟨n, h⟩ /-- The `n`th coefficient of a formal power series is `0` if `n` is strictly @@ -95,28 +90,26 @@ theorem coeff_of_lt_order (n : ℕ) (h : ↑n < order φ) : coeff R n φ = 0 := /-- The `0` power series is the unique power series with infinite order. -/ @[simp] -theorem order_eq_top {φ : R⟦X⟧} : φ.order = ⊤ ↔ φ = 0 := - PartENat.not_dom_iff_eq_top.symm.trans order_finite_iff_ne_zero.not_left +theorem order_eq_top {φ : R⟦X⟧} : φ.order = ⊤ ↔ φ = 0 := by + simpa using order_finite_iff_ne_zero.not_left /-- The order of a formal power series is at least `n` if the `i`th coefficient is `0` for all `i < n`. -/ theorem nat_le_order (φ : R⟦X⟧) (n : ℕ) (h : ∀ i < n, coeff R i φ = 0) : ↑n ≤ order φ := by by_contra H; rw [not_le] at H - have : (order φ).Dom := PartENat.dom_of_le_natCast H.le - rw [← PartENat.natCast_get this, PartENat.coe_lt_coe] at H - exact coeff_order this (h _ H) + have lt_top : order φ < ⊤ := lt_top_of_lt H + replace H : (order φ).lift lt_top < n := by simpa + exact coeff_order lt_top (h _ H) /-- The order of a formal power series is at least `n` if the `i`th coefficient is `0` for all `i < n`. -/ -theorem le_order (φ : R⟦X⟧) (n : PartENat) (h : ∀ i : ℕ, ↑i < n → coeff R i φ = 0) : +theorem le_order (φ : R⟦X⟧) (n : ℕ∞) (h : ∀ i : ℕ, ↑i < n → coeff R i φ = 0) : n ≤ order φ := by - induction n using PartENat.casesOn - · show _ ≤ _ - rw [top_le_iff, order_eq_top] - ext i - exact h _ (PartENat.natCast_lt_top i) - · apply nat_le_order - simpa only [PartENat.coe_lt_coe] using h + cases n with + | top => simpa using ext (by simpa using h) + | coe n => + convert nat_le_order φ n _ + simpa using h /-- The order of a formal power series is exactly `n` if the `n`th coefficient is nonzero, and the `i`th coefficient is `0` for all `i < n`. -/ @@ -124,25 +117,17 @@ theorem order_eq_nat {φ : R⟦X⟧} {n : ℕ} : order φ = n ↔ coeff R n φ ≠ 0 ∧ ∀ i, i < n → coeff R i φ = 0 := by classical rcases eq_or_ne φ 0 with (rfl | hφ) - · simpa [(coeff R _).map_zero] using (PartENat.natCast_ne_top _).symm + · simp simp [order, dif_neg hφ, Nat.find_eq_iff] /-- The order of a formal power series is exactly `n` if the `n`th coefficient is nonzero, and the `i`th coefficient is `0` for all `i < n`. -/ -theorem order_eq {φ : R⟦X⟧} {n : PartENat} : +theorem order_eq {φ : R⟦X⟧} {n : ℕ∞} : order φ = n ↔ (∀ i : ℕ, ↑i = n → coeff R i φ ≠ 0) ∧ ∀ i : ℕ, ↑i < n → coeff R i φ = 0 := by - induction n using PartENat.casesOn - · rw [order_eq_top] - constructor - · rintro rfl - constructor <;> intros - · exfalso - exact PartENat.natCast_ne_top ‹_› ‹_› - · exact (coeff _ _).map_zero - · rintro ⟨_h₁, h₂⟩ - ext i - exact h₂ i (PartENat.natCast_lt_top i) - · simpa [PartENat.natCast_inj] using order_eq_nat + cases n with + | top => simp [ext_iff] + | coe n => simp [order_eq_nat] + /-- The order of the sum of two formal power series is at least the minimum of their orders. -/ @@ -197,14 +182,14 @@ alias order_mul_ge := le_order_mul /-- The order of the monomial `a*X^n` is infinite if `a = 0` and `n` otherwise. -/ theorem order_monomial (n : ℕ) (a : R) [Decidable (a = 0)] : - order (monomial R n a) = if a = 0 then (⊤ : PartENat) else n := by + order (monomial R n a) = if a = 0 then (⊤ : ℕ∞) else n := by split_ifs with h · rw [h, order_eq_top, LinearMap.map_zero] · rw [order_eq] constructor <;> intro i hi - · rw [PartENat.natCast_inj] at hi + · simp only [Nat.cast_inj] at hi rwa [hi, coeff_monomial_same] - · rw [PartENat.coe_lt_coe] at hi + · simp only [Nat.cast_lt] at hi rw [coeff_monomial, if_neg] exact ne_of_lt hi @@ -242,42 +227,42 @@ theorem coeff_mul_prod_one_sub_of_lt_order {R ι : Type*} [CommRing R] (k : ℕ) exact ih t.2 -- TODO: link with `X_pow_dvd_iff` -theorem X_pow_order_dvd (h : (order φ).Dom) : X ^ (order φ).get h ∣ φ := by - refine ⟨PowerSeries.mk fun n => coeff R (n + (order φ).get h) φ, ?_⟩ +theorem X_pow_order_dvd (h : order φ < ⊤) : X ^ (order φ).lift h ∣ φ := by + refine ⟨PowerSeries.mk fun n => coeff R (n + (order φ).lift h) φ, ?_⟩ ext n simp only [coeff_mul, coeff_X_pow, coeff_mk, boole_mul, Finset.sum_ite, Finset.sum_const_zero, add_zero] - rw [Finset.filter_fst_eq_antidiagonal n (Part.get (order φ) h)] + rw [Finset.filter_fst_eq_antidiagonal n ((order φ).lift h)] split_ifs with hn · simp [tsub_add_cancel_of_le hn] · simp only [Finset.sum_empty] refine coeff_of_lt_order _ ?_ - simpa [PartENat.coe_lt_iff] using fun _ => hn + simpa using hn theorem order_eq_emultiplicity_X {R : Type*} [Semiring R] (φ : R⟦X⟧) : order φ = emultiplicity X φ := by classical rcases eq_or_ne φ 0 with (rfl | hφ) · simp - induction' ho : order φ using PartENat.casesOn with n - · simp [hφ] at ho - have hn : φ.order.get (order_finite_iff_ne_zero.mpr hφ) = n := by simp [ho] - rw [← hn, ← PartENat.ofENat_coe, eq_comm] - congr 1 - apply le_antisymm _ - · apply le_emultiplicity_of_pow_dvd - apply X_pow_order_dvd - · apply Order.le_of_lt_add_one - rw [← not_le, ← Nat.cast_one, ← Nat.cast_add, ← pow_dvd_iff_le_emultiplicity] - rintro ⟨ψ, H⟩ - have := congr_arg (coeff R n) H - rw [← (ψ.commute_X.pow_right _).eq, coeff_mul_of_lt_order, ← hn] at this - · exact coeff_order _ this - · rw [X_pow_eq, order_monomial] - split_ifs - · exact PartENat.natCast_lt_top _ - · rw [← hn, PartENat.coe_lt_coe] - exact Nat.lt_succ_self _ + cases ho : order φ with + | top => simp [hφ] at ho + | coe n => + have hn : φ.order.lift (order_finite_iff_ne_zero.mpr hφ) = n := by simp [ho] + rw [← hn, eq_comm] + apply le_antisymm _ + · apply le_emultiplicity_of_pow_dvd + apply X_pow_order_dvd + · apply Order.le_of_lt_add_one + rw [← not_le, ← Nat.cast_one, ← Nat.cast_add, ← pow_dvd_iff_le_emultiplicity] + rintro ⟨ψ, H⟩ + have := congr_arg (coeff R n) H + rw [← (ψ.commute_X.pow_right _).eq, coeff_mul_of_lt_order, ← hn] at this + · exact coeff_order _ this + · rw [X_pow_eq, order_monomial] + split_ifs + · simp + · rw [← hn, ENat.coe_lt_coe] + simp /-- Given a non-zero power series `f`, `divided_by_X_pow_order f` is the power series obtained by dividing out the largest power of X that divides `f`, that is its order -/ @@ -285,7 +270,7 @@ def divided_by_X_pow_order {f : PowerSeries R} (hf : f ≠ 0) : R⟦X⟧ := (exists_eq_mul_right_of_dvd (X_pow_order_dvd (order_finite_iff_ne_zero.2 hf))).choose theorem self_eq_X_pow_order_mul_divided_by_X_pow_order {f : R⟦X⟧} (hf : f ≠ 0) : - X ^ f.order.get (order_finite_iff_ne_zero.mpr hf) * divided_by_X_pow_order hf = f := + X ^ f.order.lift (order_finite_iff_ne_zero.mpr hf) * divided_by_X_pow_order hf = f := haveI dvd := X_pow_order_dvd (order_finite_iff_ne_zero.mpr hf) (exists_eq_mul_right_of_dvd dvd).choose_spec.symm @@ -329,28 +314,24 @@ variable [CommRing R] [IsDomain R] is the sum of their orders. -/ theorem order_mul (φ ψ : R⟦X⟧) : order (φ * ψ) = order φ + order ψ := by classical - simp_rw [order_eq_emultiplicity_X] - change PartENat.withTopAddEquiv.symm _ = - PartENat.withTopAddEquiv.symm _ + PartENat.withTopAddEquiv.symm _ - rw [← map_add] - congr 1 - exact emultiplicity_mul X_prime + simp only [order_eq_emultiplicity_X] + rw [emultiplicity_mul X_prime] -- Dividing `X` by the maximal power of `X` dividing it leaves `1`. @[simp] theorem divided_by_X_pow_order_of_X_eq_one : divided_by_X_pow_order X_ne_zero = (1 : R⟦X⟧) := by rw [← mul_eq_left₀ X_ne_zero] - simpa only [order_X, X_ne_zero, PartENat.get_one, pow_one, Ne, not_false_iff] using - self_eq_X_pow_order_mul_divided_by_X_pow_order (@X_ne_zero R _ _) + simpa using self_eq_X_pow_order_mul_divided_by_X_pow_order (@X_ne_zero R _ _) -- Dividing a power series by the maximal power of `X` dividing it, respects multiplication. theorem divided_by_X_pow_orderMul {f g : R⟦X⟧} (hf : f ≠ 0) (hg : g ≠ 0) : divided_by_X_pow_order hf * divided_by_X_pow_order hg = divided_by_X_pow_order (mul_ne_zero hf hg) := by - set df := f.order.get (order_finite_iff_ne_zero.mpr hf) - set dg := g.order.get (order_finite_iff_ne_zero.mpr hg) - set dfg := (f * g).order.get (order_finite_iff_ne_zero.mpr (mul_ne_zero hf hg)) with hdfg - have H_add_d : df + dg = dfg := by simp_all only [PartENat.get_add, order_mul f g] + set df := f.order.lift (order_finite_iff_ne_zero.mpr hf) + set dg := g.order.lift (order_finite_iff_ne_zero.mpr hg) + set dfg := (f * g).order.lift (order_finite_iff_ne_zero.mpr (mul_ne_zero hf hg)) + have H_add_d : df + dg = dfg := by + simp_all [df, dg, dfg, order_mul f g] have H := self_eq_X_pow_order_mul_divided_by_X_pow_order (mul_ne_zero hf hg) have : f * g = X ^ dfg * (divided_by_X_pow_order hf * divided_by_X_pow_order hg) := by calc diff --git a/Mathlib/RingTheory/PowerSeries/PiTopology.lean b/Mathlib/RingTheory/PowerSeries/PiTopology.lean new file mode 100644 index 0000000000000..b3cf011bd7091 --- /dev/null +++ b/Mathlib/RingTheory/PowerSeries/PiTopology.lean @@ -0,0 +1,205 @@ +/- +Copyright (c) 2024 Antoine Chambert-Loir, María Inés de Frutos-Fernández. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Antoine Chambert-Loir, María Inés de Frutos-Fernández +-/ +import Mathlib.RingTheory.MvPowerSeries.PiTopology +import Mathlib.RingTheory.PowerSeries.Basic +import Mathlib.LinearAlgebra.Finsupp.Pi + +/-! # Product topology on power series + +Let `R` be with `Semiring R` and `TopologicalSpace R` +In this file we define the topology on `PowerSeries σ R` +that corresponds to the simple convergence on its coefficients. +It is the coarsest topology for which all coefficients maps are continuous. + +When `R` has `UniformSpace R`, we define the corresponding uniform structure. + +This topology can be included by writing `open scoped PowerSeries.WithPiTopology`. + +When the type of coefficients has the discrete topology, +it corresponds to the topology defined by [bourbaki1981], chapter 4, §4, n°2. + +It corresponds with the adic topology but this is not proved here. + +- `PowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_nilpotent`, +`PowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_zero`: if the constant coefficient +of `f` is nilpotent, or vanishes, then the powers of `f` converge to zero. + +- `PowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_nilpotent_iff` : the powers of `f` +converge to zero iff the constant coefficient of `f` is nilpotent. + +- `PowerSeries.WithPiTopology.hasSum_of_monomials_self` : viewed as an infinite sum, a power +series coverges to itself. + +TODO: add the similar result for the series of homogeneous components. + +## Instances + +- If `R` is a topological (semi)ring, then so is `PowerSeries σ R`. +- If the topology of `R` is T0 or T2, then so is that of `PowerSeries σ R`. +- If `R` is a `UniformAddGroup`, then so is `PowerSeries σ R`. +- If `R` is complete, then so is `PowerSeries σ R`. + +-/ + + +namespace PowerSeries + +open Filter Function + +variable (R : Type*) + +section Topological + +variable [TopologicalSpace R] + +namespace WithPiTopology + +/-- The pointwise topology on `PowerSeries` -/ +scoped instance : TopologicalSpace (PowerSeries R) := + Pi.topologicalSpace + +/-- Separation of the topology on `PowerSeries` -/ +@[scoped instance] +theorem instT0Space [T0Space R] : T0Space (PowerSeries R) := + MvPowerSeries.WithPiTopology.instT0Space + +/-- `PowerSeries` on a `T2Space` form a `T2Space` -/ +@[scoped instance] +theorem instT2Space [T2Space R] : T2Space (PowerSeries R) := + MvPowerSeries.WithPiTopology.instT2Space + +/-- Coefficients are continuous -/ +theorem continuous_coeff [Semiring R] (d : ℕ) : Continuous (PowerSeries.coeff R d) := + continuous_pi_iff.mp continuous_id (Finsupp.single () d) + +/-- The constant coefficient is continuous -/ +theorem continuous_constantCoeff [Semiring R] : Continuous (constantCoeff R) := + coeff_zero_eq_constantCoeff (R := R) ▸ continuous_coeff R 0 + +/-- A family of power series converges iff it converges coefficientwise -/ +theorem tendsto_iff_coeff_tendsto [Semiring R] {ι : Type*} + (f : ι → PowerSeries R) (u : Filter ι) (g : PowerSeries R) : + Tendsto f u (nhds g) ↔ + ∀ d : ℕ, Tendsto (fun i => coeff R d (f i)) u (nhds (coeff R d g)) := by + rw [MvPowerSeries.WithPiTopology.tendsto_iff_coeff_tendsto] + apply (Finsupp.LinearEquiv.finsuppUnique ℕ ℕ Unit).toEquiv.forall_congr + intro d + simp only [LinearEquiv.coe_toEquiv, Finsupp.LinearEquiv.finsuppUnique_apply, + PUnit.default_eq_unit, coeff] + apply iff_of_eq + congr + · ext _; congr; ext; simp + · ext; simp + +/-- The semiring topology on `PowerSeries` of a topological semiring -/ +@[scoped instance] +theorem instTopologicalSemiring [Semiring R] [TopologicalSemiring R] : + TopologicalSemiring (PowerSeries R) := + MvPowerSeries.WithPiTopology.instTopologicalSemiring Unit R + +/-- The ring topology on `PowerSeries` of a topological ring -/ +@[scoped instance] +theorem instTopologicalRing [Ring R] [TopologicalRing R] : + TopologicalRing (PowerSeries R) := + MvPowerSeries.WithPiTopology.instTopologicalRing Unit R + +end WithPiTopology + +end Topological + +section Uniform + +namespace WithPiTopology + +variable [UniformSpace R] + +/-- The product uniformity on `PowerSeries` -/ +scoped instance : UniformSpace (PowerSeries R) := + MvPowerSeries.WithPiTopology.instUniformSpace + +/-- Coefficients are uniformly continuous -/ +theorem uniformContinuous_coeff [Semiring R] (d : ℕ) : + UniformContinuous fun f : PowerSeries R ↦ coeff R d f := + uniformContinuous_pi.mp uniformContinuous_id (Finsupp.single () d) + +/-- Completeness of the uniform structure on `PowerSeries` -/ +@[scoped instance] +theorem instCompleteSpace [CompleteSpace R] : + CompleteSpace (PowerSeries R) := + MvPowerSeries.WithPiTopology.instCompleteSpace + +/-- The `UniformAddGroup` structure on `PowerSeries` of a `UniformAddGroup` -/ +@[scoped instance] +theorem instUniformAddGroup [AddGroup R] [UniformAddGroup R] : + UniformAddGroup (PowerSeries R) := + MvPowerSeries.WithPiTopology.instUniformAddGroup + +end WithPiTopology + +end Uniform + +section + +variable {R} + +variable [TopologicalSpace R] + +namespace WithPiTopology + +open MvPowerSeries.WithPiTopology + +theorem continuous_C [Semiring R] : Continuous (C R) := + MvPowerSeries.WithPiTopology.continuous_C + +theorem tendsto_pow_zero_of_constantCoeff_nilpotent [CommSemiring R] + {f : PowerSeries R} (hf : IsNilpotent (constantCoeff R f)) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) := + MvPowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_nilpotent hf + +theorem tendsto_pow_zero_of_constantCoeff_zero [CommSemiring R] + {f : PowerSeries R} (hf : constantCoeff R f = 0) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) := + MvPowerSeries.WithPiTopology.tendsto_pow_zero_of_constantCoeff_zero hf + +/-- The powers of a `PowerSeries` converge to 0 iff its constant coefficient is nilpotent. +N. Bourbaki, *Algebra II*, [bourbaki1981] (chap. 4, §4, n°2, corollaire de la prop. 3) -/ +theorem tendsto_pow_zero_of_constantCoeff_nilpotent_iff + [CommRing R] [DiscreteTopology R] (f : PowerSeries R) : + Tendsto (fun n : ℕ => f ^ n) atTop (nhds 0) ↔ + IsNilpotent (constantCoeff R f) := + MvPowerSeries.WithPiTopology.tendsto_pow_of_constantCoeff_nilpotent_iff f + +end WithPiTopology + +end + +section Summable + +variable [Semiring R] [TopologicalSpace R] + +open WithPiTopology MvPowerSeries.WithPiTopology + +variable {R} + +-- NOTE : one needs an API to apply `Finsupp.LinearEquiv.finsuppUnique` +/-- A power series is the sum (in the sense of summable families) of its monomials -/ +theorem hasSum_of_monomials_self (f : PowerSeries R) : + HasSum (fun d : ℕ => monomial R d (coeff R d f)) f := by + rw [← (Finsupp.LinearEquiv.finsuppUnique ℕ ℕ Unit).toEquiv.hasSum_iff] + convert MvPowerSeries.WithPiTopology.hasSum_of_monomials_self f + simp only [LinearEquiv.coe_toEquiv, comp_apply, monomial, coeff, + Finsupp.LinearEquiv.finsuppUnique_apply, PUnit.default_eq_unit] + congr + all_goals { ext; simp } + +/-- If the coefficient space is T2, then the power series is `tsum` of its monomials -/ +theorem as_tsum [T2Space R] (f : PowerSeries R) : + f = tsum fun d : ℕ => monomial R d (coeff R d f) := + (HasSum.tsum_eq (hasSum_of_monomials_self f)).symm + +end Summable + +end PowerSeries diff --git a/Mathlib/RingTheory/PowerSeries/WellKnown.lean b/Mathlib/RingTheory/PowerSeries/WellKnown.lean index ef67977a0a5d2..783e6348c6aa9 100644 --- a/Mathlib/RingTheory/PowerSeries/WellKnown.lean +++ b/Mathlib/RingTheory/PowerSeries/WellKnown.lean @@ -151,15 +151,26 @@ theorem invOneSubPow_inv_eq_one_sub_pow : | zero => exact Eq.symm <| pow_zero _ | succ d => rfl -theorem invOneSubPow_inv_eq_one_of_eq_zero (h : d = 0) : - (invOneSubPow S d).inv = 1 := by +theorem invOneSubPow_inv_zero_eq_one : (invOneSubPow S 0).inv = 1 := by delta invOneSubPow - simp only [h, Units.inv_eq_val_inv, inv_one, Units.val_one] + simp only [Units.inv_eq_val_inv, inv_one, Units.val_one] theorem mk_add_choose_mul_one_sub_pow_eq_one : (mk fun n ↦ Nat.choose (d + n) d : S⟦X⟧) * ((1 - X) ^ (d + 1)) = 1 := (invOneSubPow S (d + 1)).val_inv +theorem invOneSubPow_add (e : ℕ) : + invOneSubPow S (d + e) = invOneSubPow S d * invOneSubPow S e := by + simp_rw [invOneSubPow_eq_inv_one_sub_pow, pow_add] + +theorem one_sub_pow_mul_invOneSubPow_val_add_eq_invOneSubPow_val (e : ℕ) : + (1 - X) ^ e * (invOneSubPow S (d + e)).val = (invOneSubPow S d).val := by + simp [invOneSubPow_add, Units.val_mul, mul_comm, mul_assoc, ← invOneSubPow_inv_eq_one_sub_pow] + +theorem one_sub_pow_add_mul_invOneSubPow_val_eq_one_sub_pow (e : ℕ) : + (1 - X) ^ (d + e) * (invOneSubPow S e).val = (1 - X) ^ d := by + simp [pow_add, mul_assoc, ← invOneSubPow_inv_eq_one_sub_pow S e] + end invOneSubPow section Field diff --git a/Mathlib/RingTheory/PrimeSpectrum.lean b/Mathlib/RingTheory/PrimeSpectrum.lean index 5ac44c10a7f5f..f4f648dbb34cc 100644 --- a/Mathlib/RingTheory/PrimeSpectrum.lean +++ b/Mathlib/RingTheory/PrimeSpectrum.lean @@ -563,6 +563,59 @@ theorem localization_specComap_range [Algebra R S] (M : Submonoid R) [IsLocaliza ext1 exact IsLocalization.comap_map_of_isPrime_disjoint M S _ x.2 h +section Pi + +variable {ι} (R : ι → Type*) [∀ i, CommSemiring (R i)] + +/-- The canonical map from a disjoint union of prime spectra of commutative semirings to +the prime spectrum of the product semiring. -/ +/- TODO: show this is always a topological embedding (even when ι is infinite) +and is a homeomorphism when ι is finite. -/ +@[simps] def sigmaToPi : (Σ i, PrimeSpectrum (R i)) → PrimeSpectrum (Π i, R i) + | ⟨i, p⟩ => (Pi.evalRingHom R i).specComap p + +theorem sigmaToPi_injective : (sigmaToPi R).Injective := fun ⟨i, p⟩ ⟨j, q⟩ eq ↦ by + obtain rfl | ne := eq_or_ne i j + · congr; ext x + simpa using congr_arg (Function.update (0 : ∀ i, R i) i x ∈ ·.asIdeal) eq + · refine (p.1.ne_top_iff_one.mp p.2.ne_top ?_).elim + have : Function.update (1 : ∀ i, R i) j 0 ∈ (sigmaToPi R ⟨j, q⟩).asIdeal := by simp + simpa [← eq, Function.update_noteq ne] + +variable [Infinite ι] [∀ i, Nontrivial (R i)] + +/-- An infinite product of nontrivial commutative semirings has a maximal ideal outside of the +range of `sigmaToPi`, i.e. is not of the form `πᵢ⁻¹(𝔭)` for some prime `𝔭 ⊂ R i`, where +`πᵢ : (Π i, R i) →+* R i` is the projection. For a complete description of all prime ideals, +see https://math.stackexchange.com/a/1563190. -/ +theorem exists_maximal_nmem_range_sigmaToPi_of_infinite : + ∃ (I : Ideal (Π i, R i)) (_ : I.IsMaximal), ⟨I, inferInstance⟩ ∉ Set.range (sigmaToPi R) := by + let J : Ideal (Π i, R i) := -- `J := Π₀ i, R i` is an ideal in `Π i, R i` + { __ := AddMonoidHom.mrange DFinsupp.coeFnAddMonoidHom + smul_mem' := by + rintro r _ ⟨x, rfl⟩ + refine ⟨.mk x.support fun i ↦ r i * x i, funext fun i ↦ show dite _ _ _ = _ from ?_⟩ + simp_rw [DFinsupp.coeFnAddMonoidHom] + refine dite_eq_left_iff.mpr fun h ↦ ?_ + rw [DFinsupp.not_mem_support_iff.mp h, mul_zero] } + have ⟨I, max, le⟩ := J.exists_le_maximal <| (Ideal.ne_top_iff_one _).mpr <| by + -- take a maximal ideal I containing J + rintro ⟨x, hx⟩ + have ⟨i, hi⟩ := x.support.exists_not_mem + simpa [DFinsupp.coeFnAddMonoidHom, DFinsupp.not_mem_support_iff.mp hi] using congr_fun hx i + refine ⟨I, max, fun ⟨⟨i, p⟩, eq⟩ ↦ ?_⟩ + -- then I is not in the range of `sigmaToPi` + have : ⇑(DFinsupp.single i 1) ∉ (sigmaToPi R ⟨i, p⟩).asIdeal := by + simpa using p.1.ne_top_iff_one.mp p.2.ne_top + rw [eq] at this + exact this (le ⟨.single i 1, rfl⟩) + +theorem sigmaToPi_not_surjective_of_infinite : ¬ (sigmaToPi R).Surjective := fun surj ↦ + have ⟨_, _, nmem⟩ := exists_maximal_nmem_range_sigmaToPi_of_infinite R + (Set.range_eq_univ.mpr surj ▸ nmem) ⟨⟩ + +end Pi + end PrimeSpectrum section SpecOfSurjective diff --git a/Mathlib/RingTheory/RingHom/FinitePresentation.lean b/Mathlib/RingTheory/RingHom/FinitePresentation.lean index 195c2d6891823..f2503b3b0b8f9 100644 --- a/Mathlib/RingTheory/RingHom/FinitePresentation.lean +++ b/Mathlib/RingTheory/RingHom/FinitePresentation.lean @@ -151,7 +151,7 @@ theorem finitePresentation_ofLocalizationSpanTarget : have : ∃ (a : S) (hb : a ∈ s), (Ideal.Quotient.mk I) (g' ⟨a, hb⟩) = g.val := by obtain ⟨g, hg⟩ := g convert hg - simp [t] + simp [A, f', t] obtain ⟨r, hr, hrr⟩ := this simp only [f'] rw [← hrr, Ideal.Quotient.liftₐ_apply, Ideal.Quotient.lift_mk] diff --git a/Mathlib/RingTheory/RingHom/Flat.lean b/Mathlib/RingTheory/RingHom/Flat.lean new file mode 100644 index 0000000000000..ee70f2de16d6b --- /dev/null +++ b/Mathlib/RingTheory/RingHom/Flat.lean @@ -0,0 +1,71 @@ +/- +Copyright (c) 2024 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten +-/ +import Mathlib.RingTheory.Flat.Localization +import Mathlib.RingTheory.LocalProperties.Basic + +/-! +# Flat ring homomorphisms + +In this file we define flat ring homomorphisms and show their meta properties. + +-/ + +universe u v + +open TensorProduct + +/-- A ring homomorphism `f : R →+* S` is flat if `S` is flat as an `R` module. -/ +@[algebraize Module.Flat] +def RingHom.Flat {R : Type u} {S : Type v} [CommRing R] [CommRing S] (f : R →+* S) : Prop := + letI : Algebra R S := f.toAlgebra + Module.Flat R S + +namespace RingHom.Flat + +variable {R S T : Type*} [CommRing R] [CommRing S] [CommRing T] + +variable (R) in +/-- The identity of a ring is flat. -/ +lemma id : RingHom.Flat (RingHom.id R) := + Module.Flat.self R + +/-- Composition of flat ring homomorphisms is flat. -/ +lemma comp {f : R →+* S} {g : S →+* T} (hf : f.Flat) (hg : g.Flat) : Flat (g.comp f) := by + algebraize [f, g, (g.comp f)] + exact Module.Flat.trans R S T + +/-- Bijective ring maps are flat. -/ +lemma of_bijective {f : R →+* S} (hf : Function.Bijective f) : Flat f := by + algebraize [f] + exact Module.Flat.of_linearEquiv R R S (LinearEquiv.ofBijective (Algebra.linearMap R S) hf).symm + +lemma containsIdentities : ContainsIdentities Flat := id + +lemma stableUnderComposition : StableUnderComposition Flat := by + introv R hf hg + exact hf.comp hg + +lemma respectsIso : RespectsIso Flat := by + apply stableUnderComposition.respectsIso + introv + exact of_bijective e.bijective + +lemma isStableUnderBaseChange : IsStableUnderBaseChange Flat := by + apply IsStableUnderBaseChange.mk _ respectsIso + introv h + replace h : Module.Flat R T := by + rw [RingHom.Flat] at h; convert h; ext; simp_rw [Algebra.smul_def]; rfl + suffices Module.Flat S (S ⊗[R] T) by + rw [RingHom.Flat]; convert this; congr; ext; simp_rw [Algebra.smul_def]; rfl + exact inferInstance + +lemma holdsForLocalizationAway : HoldsForLocalizationAway Flat := by + introv R h + suffices Module.Flat R S by + rw [RingHom.Flat]; convert this; ext; simp_rw [Algebra.smul_def]; rfl + exact IsLocalization.flat _ (Submonoid.powers r) + +end RingHom.Flat diff --git a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean index 34a8597d9b708..2da9825d08c25 100644 --- a/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean +++ b/Mathlib/RingTheory/RootsOfUnity/Minpoly.lean @@ -150,7 +150,7 @@ theorem minpoly_eq_pow {p : ℕ} [hprime : Fact p.Prime] (hdiv : ¬p ∣ n) : (separable_X_pow_sub_C 1 (fun h => hdiv <| (ZMod.natCast_zmod_eq_zero_iff_dvd n p).1 h) one_ne_zero).squarefree cases' - (multiplicity.squarefree_iff_emultiplicity_le_one (X ^ n - 1)).1 hfree + (squarefree_iff_emultiplicity_le_one (X ^ n - 1)).1 hfree (map (Int.castRingHom (ZMod p)) P) with hle hunit · rw [Nat.cast_one] at habs; exact hle.not_lt habs @@ -217,7 +217,7 @@ theorem totient_le_degree_minpoly : Nat.totient n ≤ (minpoly ℤ μ).natDegree _ ≤ 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 _ _ + _ ≤ P.natDegree := natDegree_map_le end IsDomain diff --git a/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean b/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean index 8399113e64d64..f1f8616f7cb18 100644 --- a/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean +++ b/Mathlib/RingTheory/RootsOfUnity/PrimitiveRoots.lean @@ -363,7 +363,7 @@ theorem primitiveRoots_one : primitiveRoots 1 R = {(1 : R)} := by theorem neZero' {n : ℕ} [NeZero n] (hζ : IsPrimitiveRoot ζ n) : NeZero ((n : ℕ) : R) := by let p := ringChar R - have hfin := Nat.multiplicity_finite_iff.2 ⟨CharP.char_ne_one R p, NeZero.pos n⟩ + have hfin := Nat.finiteMultiplicity_iff.2 ⟨CharP.char_ne_one R p, NeZero.pos n⟩ obtain ⟨m, hm⟩ := hfin.exists_eq_pow_mul_and_not_dvd by_cases hp : p ∣ n · obtain ⟨k, hk⟩ := Nat.exists_eq_succ_of_ne_zero (multiplicity_pos_of_dvd hp).ne' diff --git a/Mathlib/RingTheory/TensorProduct/Basic.lean b/Mathlib/RingTheory/TensorProduct/Basic.lean index 857c189049c66..7eeec368f0ac8 100644 --- a/Mathlib/RingTheory/TensorProduct/Basic.lean +++ b/Mathlib/RingTheory/TensorProduct/Basic.lean @@ -807,6 +807,53 @@ variable {A} in @[simp] theorem rid_symm_apply (a : A) : (TensorProduct.rid R S A).symm a = a ⊗ₜ 1 := rfl +section CompatibleSMul + +variable (R S A B : Type*) [CommSemiring R] [CommSemiring S] [Semiring A] [Semiring B] +variable [Algebra R A] [Algebra R B] [Algebra S A] [Algebra S B] +variable [SMulCommClass R S A] [CompatibleSMul R S A B] + +/-- If A and B are both R- and S-algebras and their actions on them commute, +and if the S-action on `A ⊗[R] B` can switch between the two factors, then there is a +canonical S-algebra homomorphism from `A ⊗[S] B` to `A ⊗[R] B`. -/ +def mapOfCompatibleSMul : A ⊗[S] B →ₐ[S] A ⊗[R] B := + .ofLinearMap (_root_.TensorProduct.mapOfCompatibleSMul R S A B) rfl fun x ↦ + x.induction_on (by simp) (fun _ _ y ↦ y.induction_on (by simp) (by simp) + fun _ _ h h' ↦ by simp only [mul_add, map_add, h, h']) + fun _ _ h h' _ ↦ by simp only [add_mul, map_add, h, h'] + +@[simp] theorem mapOfCompatibleSMul_tmul (m n) : mapOfCompatibleSMul R S A B (m ⊗ₜ n) = m ⊗ₜ n := + rfl + +theorem mapOfCompatibleSMul_surjective : Function.Surjective (mapOfCompatibleSMul R S A B) := + _root_.TensorProduct.mapOfCompatibleSMul_surjective R S A B + +attribute [local instance] SMulCommClass.symm + +/-- `mapOfCompatibleSMul R S A B` is also A-linear. -/ +def mapOfCompatibleSMul' : A ⊗[S] B →ₐ[R] A ⊗[R] B := + .ofLinearMap (_root_.TensorProduct.mapOfCompatibleSMul' R S A B) rfl + (map_mul <| mapOfCompatibleSMul R S A B) + +/-- If the R- and S-actions on A and B satisfy `CompatibleSMul` both ways, +then `A ⊗[S] B` is canonically isomorphic to `A ⊗[R] B`. -/ +def equivOfCompatibleSMul [CompatibleSMul S R A B] : A ⊗[S] B ≃ₐ[S] A ⊗[R] B where + __ := mapOfCompatibleSMul R S A B + invFun := mapOfCompatibleSMul S R A B + __ := _root_.TensorProduct.equivOfCompatibleSMul R S A B + +variable [Algebra R S] [CompatibleSMul R S S A] [CompatibleSMul S R S A] +omit [SMulCommClass R S A] + +/-- If the R- and S- action on S and A satisfy `CompatibleSMul` both ways, +then `S ⊗[R] A` is canonically isomorphic to `A`. -/ +def lidOfCompatibleSMul : S ⊗[R] A ≃ₐ[S] A := + (equivOfCompatibleSMul R S S A).symm.trans (TensorProduct.lid _ _) + +theorem lidOfCompatibleSMul_tmul (s a) : lidOfCompatibleSMul R S A (s ⊗ₜ[R] a) = s • a := rfl + +end CompatibleSMul + section variable (B) @@ -1054,6 +1101,10 @@ def lmul'' : S ⊗[R] S →ₐ[S] S := fun x y hx hy ↦ by simp_all [hx, hy, mul_add] } (fun a₁ a₂ b₁ b₂ => by simp [mul_mul_mul_comm]) <| by simp +theorem lmul''_eq_lid_comp_mapOfCompatibleSMul : + lmul'' R = (TensorProduct.lid S S).toAlgHom.comp (mapOfCompatibleSMul' _ _ _ _) := by + ext; rfl + /-- `LinearMap.mul'` as an `AlgHom` over the base ring. -/ def lmul' : S ⊗[R] S →ₐ[R] S := (lmul'' R).restrictScalars R @@ -1083,6 +1134,10 @@ def lmulEquiv [CompatibleSMul R S S S] : S ⊗[R] S ≃ₐ[S] S := rw [mul_comm, ← smul_eq_mul, smul_tmul, smul_eq_mul, mul_one]) fun _ _ hx hy ↦ by simp_all [hx, hy, add_tmul] +theorem lmulEquiv_eq_lidOfCompatibleSMul [CompatibleSMul R S S S] : + lmulEquiv R S = lidOfCompatibleSMul R S S := + AlgEquiv.coe_algHom_injective <| by ext; rfl + /-- If `S` is commutative, for a pair of morphisms `f : A →ₐ[R] S`, `g : B →ₐ[R] S`, We obtain a map `A ⊗[R] B →ₐ[R] S` that commutes with `f`, `g` via `a ⊗ b ↦ f(a) * g(b)`. diff --git a/Mathlib/RingTheory/TensorProduct/Free.lean b/Mathlib/RingTheory/TensorProduct/Free.lean index a857cfdf874c6..a58fc59512f2a 100644 --- a/Mathlib/RingTheory/TensorProduct/Free.lean +++ b/Mathlib/RingTheory/TensorProduct/Free.lean @@ -22,6 +22,8 @@ and deducde that `Module.Free` is stable under base change. -/ +assert_not_exists Cardinal + suppress_compilation open scoped TensorProduct diff --git a/Mathlib/RingTheory/TensorProduct/Nontrivial.lean b/Mathlib/RingTheory/TensorProduct/Nontrivial.lean new file mode 100644 index 0000000000000..ee304a244cbe6 --- /dev/null +++ b/Mathlib/RingTheory/TensorProduct/Nontrivial.lean @@ -0,0 +1,41 @@ +/- +Copyright (c) 2024 Jz Pan. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jz Pan +-/ +import Mathlib.LinearAlgebra.Basis.VectorSpace +import Mathlib.RingTheory.Flat.FaithfullyFlat +import Mathlib.RingTheory.Localization.FractionRing + +/-! + +# Nontriviality of tensor product of algebras + +This file contains some more results on nontriviality of tensor product of algebras. + +-/ + +open TensorProduct + +namespace Algebra.TensorProduct + +/-- If `A`, `B` are `R`-algebras, `R` injects into `A` and `B`, and `A` and `B` are domains +(which implies `R` is also a domain), then `A ⊗[R] B` is nontrivial. -/ +theorem nontrivial_of_algebraMap_injective_of_isDomain + (R A B : Type*) [CommRing R] [CommRing A] [CommRing B] [Algebra R A] [Algebra R B] + (ha : Function.Injective (algebraMap R A)) (hb : Function.Injective (algebraMap R B)) + [IsDomain A] [IsDomain B] : Nontrivial (A ⊗[R] B) := by + haveI := ha.isDomain _ + let FR := FractionRing R + let FA := FractionRing A + let FB := FractionRing B + let fa : FR →ₐ[R] FA := IsFractionRing.liftAlgHom (g := Algebra.ofId R FA) + ((IsFractionRing.injective A FA).comp ha) + let fb : FR →ₐ[R] FB := IsFractionRing.liftAlgHom (g := Algebra.ofId R FB) + ((IsFractionRing.injective B FB).comp hb) + algebraize_only [fa.toRingHom, fb.toRingHom] + exact Algebra.TensorProduct.mapOfCompatibleSMul FR R FA FB |>.comp + (Algebra.TensorProduct.map (IsScalarTower.toAlgHom R A FA) (IsScalarTower.toAlgHom R B FB)) + |>.toRingHom.domain_nontrivial + +end Algebra.TensorProduct diff --git a/Mathlib/RingTheory/TensorProduct/Pi.lean b/Mathlib/RingTheory/TensorProduct/Pi.lean new file mode 100644 index 0000000000000..b6b48e4414f31 --- /dev/null +++ b/Mathlib/RingTheory/TensorProduct/Pi.lean @@ -0,0 +1,58 @@ +/- +Copyright (c) 2024 Christian Merten. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Christian Merten +-/ +import Mathlib.Algebra.Algebra.Pi +import Mathlib.LinearAlgebra.TensorProduct.Pi +import Mathlib.RingTheory.TensorProduct.Basic + +/-! +# Tensor product and products of algebras + +In this file we examine the behaviour of the tensor product with (finite) products. This +is a direct application of `Mathlib.LinearAlgebra.TensorProduct.Pi` to the algebra case. + +-/ + +open TensorProduct + +section + +variable (R S A : Type*) [CommSemiring R] [CommSemiring S] [Algebra R S] [CommSemiring A] + [Algebra R A] [Algebra S A] [IsScalarTower R S A] +variable {ι : Type*} (B : ι → Type*) [∀ i, CommSemiring (B i)] [∀ i, Algebra R (B i)] + +@[simp] +lemma piRightHom_one : piRightHom R S A B 1 = 1 := rfl + +variable {R S A B} in +@[simp] +lemma piRightHom_mul (x y : A ⊗[R] ∀ i, B i) : + piRightHom R S A B (x * y) = piRightHom R S A B x * piRightHom R S A B y := by + induction x + · simp + · induction y + · simp + · ext j + simp + · simp_all [mul_add] + · simp_all [add_mul] + +/-- The canonical map `A ⊗[R] (∀ i, B i) →ₐ[S] ∀ i, A ⊗[R] B i`. This is an isomorphism +if `ι` is finite (see `Algebra.TensorProduct.piRight`). -/ +noncomputable def piRightHom : A ⊗[R] (∀ i, B i) →ₐ[S] ∀ i, A ⊗[R] B i := + AlgHom.ofLinearMap (_root_.TensorProduct.piRightHom R S A B) (by simp) (by simp) + +variable [Fintype ι] [DecidableEq ι] + +/-- Tensor product of rings commutes with finite products on the right. -/ +noncomputable def Algebra.TensorProduct.piRight : + A ⊗[R] (∀ i, B i) ≃ₐ[S] ∀ i, A ⊗[R] B i := + AlgEquiv.ofLinearEquiv (_root_.TensorProduct.piRight R S A B) (by simp) (by simp) + +@[simp] +lemma Algebra.TensorProduct.piRight_tmul (x : A) (f : ∀ i, B i) : + piRight R S A B (x ⊗ₜ f) = (fun j ↦ x ⊗ₜ f j) := rfl + +end diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean index 121cf52e3a622..28fef6a3998c7 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Defs.lean @@ -6,6 +6,7 @@ Authors: Johannes Hölzl, Jens Wagemaker, Aaron Anderson import Mathlib.Algebra.Associated.Basic import Mathlib.Algebra.BigOperators.Group.Multiset import Mathlib.Algebra.Group.Submonoid.Membership +import Mathlib.Algebra.Group.Submonoid.BigOperators import Mathlib.Order.WellFounded /-! diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean index dbc52cb56fad1..a6504ae1d7bda 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Multiplicity.lean @@ -33,11 +33,21 @@ theorem WfDvdMonoid.max_power_factor [CommMonoidWithZero α] [WfDvdMonoid α] {a (h : a₀ ≠ 0) (hx : Irreducible x) : ∃ (n : ℕ) (a : α), ¬x ∣ a ∧ a₀ = x ^ n * a := max_power_factor' h hx.not_unit -theorem multiplicity.finite_of_not_isUnit [CancelCommMonoidWithZero α] [WfDvdMonoid α] - {a b : α} (ha : ¬IsUnit a) (hb : b ≠ 0) : multiplicity.Finite a b := by +theorem FiniteMultiplicity.of_not_isUnit [CancelCommMonoidWithZero α] [WfDvdMonoid α] + {a b : α} (ha : ¬IsUnit a) (hb : b ≠ 0) : FiniteMultiplicity a b := by obtain ⟨n, c, ndvd, rfl⟩ := WfDvdMonoid.max_power_factor' hb ha exact ⟨n, by rwa [pow_succ, mul_dvd_mul_iff_left (left_ne_zero_of_mul hb)]⟩ +@[deprecated (since := "2024-11-30")] +alias multiplicity.finite_of_not_isUnit := FiniteMultiplicity.of_not_isUnit + +theorem FiniteMultiplicity.of_prime_left [CancelCommMonoidWithZero α] [WfDvdMonoid α] + {a b : α} (ha : Prime a) (hb : b ≠ 0) : FiniteMultiplicity a b := + .of_not_isUnit ha.not_unit hb + +@[deprecated (since := "2024-11-30")] +alias multiplicity.finite_prime_left := FiniteMultiplicity.of_prime_left + namespace UniqueFactorizationMonoid variable {R : Type*} [CancelCommMonoidWithZero R] [UniqueFactorizationMonoid R] diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean index 4c69bfb655b75..d8e8cd87f6ef9 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/Nat.lean @@ -27,7 +27,7 @@ instance instWfDvdMonoid : WfDvdMonoid ℕ where revert h simp [DvdNotUnit] cases b - · simpa [succ_ne_zero] using WithTop.coe_lt_top (a + 1) + · simpa [succ_ne_zero] using ENat.coe_lt_top (a + 1) cases' dvd_and_not_dvd_iff.2 h with h1 h2 simp only [succ_ne_zero, cast_lt, if_false] refine lt_of_le_of_ne (Nat.le_of_dvd (Nat.succ_pos _) h1) fun con => h2 ?_ diff --git a/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean b/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean index 3d30df0c3b813..4db1bb549e738 100644 --- a/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean +++ b/Mathlib/RingTheory/UniqueFactorizationDomain/NormalizedFactors.lean @@ -222,7 +222,7 @@ theorem mem_normalizedFactors_iff [Subsingleton αˣ] {p x : α} (hx : x ≠ 0) theorem exists_associated_prime_pow_of_unique_normalized_factor {p r : α} (h : ∀ {m}, m ∈ normalizedFactors r → m = p) (hr : r ≠ 0) : ∃ i : ℕ, Associated (p ^ i) r := by - use Multiset.card.toFun (normalizedFactors r) + use (normalizedFactors r).card have := UniqueFactorizationMonoid.normalizedFactors_prod hr rwa [Multiset.eq_replicate_of_mem fun b => h, Multiset.prod_replicate] at this diff --git a/Mathlib/RingTheory/Valuation/LocalSubring.lean b/Mathlib/RingTheory/Valuation/LocalSubring.lean index a3c86e708bac1..ae5fef7208b40 100644 --- a/Mathlib/RingTheory/Valuation/LocalSubring.lean +++ b/Mathlib/RingTheory/Valuation/LocalSubring.lean @@ -3,8 +3,9 @@ Copyright (c) 2024 Andrew Yang, Yaël Dillies, Javier López-Contreras. All righ Released under Apache 2.0 license as described in the file LICENSE. Authors: Andrew Yang, Yaël Dillies, Javier López-Contreras -/ -import Mathlib.RingTheory.LocalRing.Subring import Mathlib.RingTheory.Ideal.Over +import Mathlib.RingTheory.LocalRing.Subring +import Mathlib.RingTheory.Polynomial.Ideal import Mathlib.RingTheory.Valuation.ValuationSubring /-! diff --git a/Mathlib/RingTheory/WittVector/Frobenius.lean b/Mathlib/RingTheory/WittVector/Frobenius.lean index 79cc7194f5851..8ae9671d90379 100644 --- a/Mathlib/RingTheory/WittVector/Frobenius.lean +++ b/Mathlib/RingTheory/WittVector/Frobenius.lean @@ -124,7 +124,7 @@ theorem map_frobeniusPoly.key₂ {n i j : ℕ} (hi : i ≤ n) (hj : j < p ^ (n - 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 (pow_multiplicity_dvd _ _) exact ⟨(Nat.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)⟩ + Nat.le_of_lt_succ ((m.lt_pow_self hp.1.one_lt).trans_le hle)⟩ theorem map_frobeniusPoly (n : ℕ) : MvPolynomial.map (Int.castRingHom ℚ) (frobeniusPoly p n) = frobeniusPolyRat p n := by diff --git a/Mathlib/RingTheory/WittVector/InitTail.lean b/Mathlib/RingTheory/WittVector/InitTail.lean index a1c9c6d8601ac..0568831e3df4f 100644 --- a/Mathlib/RingTheory/WittVector/InitTail.lean +++ b/Mathlib/RingTheory/WittVector/InitTail.lean @@ -101,7 +101,7 @@ theorem select_add_select_not : ∀ x : 𝕎 R, select P x + select (fun i => ¬ refine fun m _ => mul_eq_mul_left_iff.mpr (Or.inl ?_) rw [ite_pow, zero_pow (pow_ne_zero _ hp.out.ne_zero)] by_cases Pm : P m - · rw [if_pos Pm, if_neg <| not_not_intro Pm, zero_pow Fin.size_pos'.ne', add_zero] + · rw [if_pos Pm, if_neg <| not_not_intro Pm, zero_pow Fin.pos'.ne', add_zero] · rwa [if_neg Pm, if_pos, zero_add] theorem coeff_add_of_disjoint (x y : 𝕎 R) (h : ∀ n, x.coeff n = 0 ∨ y.coeff n = 0) : diff --git a/Mathlib/RingTheory/WittVector/IsPoly.lean b/Mathlib/RingTheory/WittVector/IsPoly.lean index f6adc8664cb48..d364756920a22 100644 --- a/Mathlib/RingTheory/WittVector/IsPoly.lean +++ b/Mathlib/RingTheory/WittVector/IsPoly.lean @@ -337,20 +337,6 @@ namespace IsPoly₂ instance [Fact p.Prime] : Inhabited (IsPoly₂ p (fun _ _ => (· + ·))) := ⟨addIsPoly₂⟩ --- Porting note: maybe just drop this now that it works by `inferInstance` -/-- The composition of a binary polynomial function - with a unary polynomial function in the first argument is polynomial. -/ -theorem compLeft {g f} [IsPoly₂ p g] [IsPoly p f] : - IsPoly₂ p fun _R _Rcr x y => g (f x) y := - inferInstance - --- Porting note: maybe just drop this now that it works by `inferInstance` -/-- The composition of a binary polynomial function - with a unary polynomial function in the second argument is polynomial. -/ -theorem compRight {g f} [IsPoly₂ p g] [IsPoly p f] : - IsPoly₂ p fun _R _Rcr x y => g x (f y) := - inferInstance - theorem ext [Fact p.Prime] {f g} (hf : IsPoly₂ p f) (hg : IsPoly₂ p g) (h : ∀ (R : Type u) [_Rcr : CommRing R] (x y : 𝕎 R) (n : ℕ), ghostComponent n (f x y) = ghostComponent n (g x y)) : @@ -360,7 +346,6 @@ theorem ext [Fact p.Prime] {f g} (hf : IsPoly₂ p f) (hg : IsPoly₂ p g) intros ext n rw [hf, hg, poly_eq_of_wittPolynomial_bind_eq' p φ ψ] - -- porting note: `clear x y` does not work, since `x, y` are now hygienic intro k apply MvPolynomial.funext intro x @@ -392,8 +377,7 @@ theorem map [Fact p.Prime] {f} (hf : IsPoly₂ p f) (g : R →+* S) (x y : 𝕎 end IsPoly₂ -attribute [ghost_simps] AlgHom.map_zero AlgHom.map_one AlgHom.map_add AlgHom.map_mul AlgHom.map_sub - AlgHom.map_neg AlgHom.id_apply map_natCast RingHom.map_zero RingHom.map_one RingHom.map_mul +attribute [ghost_simps] AlgHom.id_apply map_natCast RingHom.map_zero RingHom.map_one RingHom.map_mul RingHom.map_add RingHom.map_sub RingHom.map_neg RingHom.id_apply mul_add add_mul add_zero zero_add mul_one one_mul mul_zero zero_mul Nat.succ_ne_zero add_tsub_cancel_right Nat.succ_eq_add_one if_true eq_self_iff_true if_false forall_true_iff forall₂_true_iff diff --git a/Mathlib/RingTheory/WittVector/Isocrystal.lean b/Mathlib/RingTheory/WittVector/Isocrystal.lean index 9fc53cafc60b5..38d771bf5257c 100644 --- a/Mathlib/RingTheory/WittVector/Isocrystal.lean +++ b/Mathlib/RingTheory/WittVector/Isocrystal.lean @@ -90,11 +90,11 @@ instance inv_pair₂ : RingHomInvPair ((FractionRing.frobenius p k).symm : K(p, RingHomInvPair.of_ringEquiv (FractionRing.frobenius p k).symm scoped[Isocrystal] - notation:50 M " →ᶠˡ[" p ", " k "] " M₂ => + notation3:50 M " →ᶠˡ[" p ", " k "] " M₂ => LinearMap (WittVector.FractionRing.frobeniusRingHom p k) M M₂ scoped[Isocrystal] - notation:50 M " ≃ᶠˡ[" p ", " k "] " M₂ => + notation3:50 M " ≃ᶠˡ[" p ", " k "] " M₂ => LinearEquiv (WittVector.FractionRing.frobeniusRingHom p k) M M₂ /-! ### Isocrystals -/ diff --git a/Mathlib/SetTheory/Cardinal/Aleph.lean b/Mathlib/SetTheory/Cardinal/Aleph.lean index ca79284dac29a..52eabc3d86978 100644 --- a/Mathlib/SetTheory/Cardinal/Aleph.lean +++ b/Mathlib/SetTheory/Cardinal/Aleph.lean @@ -4,7 +4,8 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios -/ import Mathlib.Order.Bounded -import Mathlib.SetTheory.Cardinal.PartENat +import Mathlib.SetTheory.Cardinal.ToNat +import Mathlib.SetTheory.Cardinal.ENat import Mathlib.SetTheory.Ordinal.Enum /-! @@ -275,7 +276,7 @@ theorem ord_preAleph (o : Ordinal) : (preAleph o).ord = preOmega o := by rw [← o.card_preOmega, (isInitial_preOmega o).ord_card] @[simp] -theorem type_cardinal : @type Cardinal (· < ·) _ = Ordinal.univ.{u, u + 1} := by +theorem type_cardinal : typeLT Cardinal = Ordinal.univ.{u, u + 1} := by rw [Ordinal.univ_id] exact Quotient.sound ⟨preAleph.symm.toRelIsoLT⟩ @@ -423,8 +424,8 @@ theorem aleph_toNat (o : Ordinal) : toNat (ℵ_ o) = 0 := toNat_apply_of_aleph0_le <| aleph0_le_aleph o @[simp] -theorem aleph_toPartENat (o : Ordinal) : toPartENat (ℵ_ o) = ⊤ := - toPartENat_apply_of_aleph0_le <| aleph0_le_aleph o +theorem aleph_toENat (o : Ordinal) : toENat (ℵ_ o) = ⊤ := + (toENat_eq_top.2 (aleph0_le_aleph o)) instance nonempty_toType_aleph (o : Ordinal) : Nonempty (ℵ_ o).ord.toType := by rw [toType_nonempty_iff_ne_zero, ← ord_zero] @@ -503,7 +504,6 @@ theorem lift_eq_aleph1 {c : Cardinal.{u}} : lift.{v} c = ℵ₁ ↔ c = ℵ₁ : section deprecated -set_option linter.deprecated false set_option linter.docPrime false @[deprecated preAleph (since := "2024-10-22")] @@ -521,6 +521,7 @@ noncomputable alias aleph' := preAleph def alephIdx.initialSeg : @InitialSeg Cardinal Ordinal (· < ·) (· < ·) := @RelEmbedding.collapse Cardinal Ordinal (· < ·) (· < ·) _ Cardinal.ord.orderEmbedding.ltEmbedding +set_option linter.deprecated false in /-- The `aleph'` index function, which gives the ordinal index of a cardinal. (The `aleph'` part is because unlike `aleph` this counts also the finite stages. So `alephIdx n = n`, `alephIdx ℵ₀ = ω`, @@ -532,6 +533,7 @@ def alephIdx.initialSeg : @InitialSeg Cardinal Ordinal (· < ·) (· < ·) := def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := aleph'.symm.toRelIsoLT +set_option linter.deprecated false in /-- The `aleph'` index function, which gives the ordinal index of a cardinal. (The `aleph'` part is because unlike `aleph` this counts also the finite stages. So `alephIdx n = n`, `alephIdx ω = ω`, @@ -541,10 +543,12 @@ def alephIdx.relIso : @RelIso Cardinal.{u} Ordinal.{u} (· < ·) (· < ·) := def alephIdx : Cardinal → Ordinal := aleph'.symm +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephIdx := rfl +set_option linter.deprecated false in /-- The `aleph'` function gives the cardinals listed by their ordinal index, and is the inverse of `aleph_idx`. `aleph' n = n`, `aleph' ω = ω`, `aleph' (ω + 1) = succ ℵ₀`, etc. @@ -555,55 +559,68 @@ theorem alephIdx.relIso_coe : (alephIdx.relIso : Cardinal → Ordinal) = alephId def Aleph'.relIso := aleph' +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem aleph'.relIso_coe : (Aleph'.relIso : Ordinal → Cardinal) = aleph' := rfl +set_option linter.deprecated false in @[deprecated preAleph_lt_preAleph (since := "2024-10-22")] theorem aleph'_lt {o₁ o₂ : Ordinal} : aleph' o₁ < aleph' o₂ ↔ o₁ < o₂ := aleph'.lt_iff_lt +set_option linter.deprecated false in @[deprecated preAleph_le_preAleph (since := "2024-10-22")] theorem aleph'_le {o₁ o₂ : Ordinal} : aleph' o₁ ≤ aleph' o₂ ↔ o₁ ≤ o₂ := aleph'.le_iff_le +set_option linter.deprecated false in @[deprecated preAleph_max (since := "2024-10-22")] theorem aleph'_max (o₁ o₂ : Ordinal) : aleph' (max o₁ o₂) = max (aleph' o₁) (aleph' o₂) := aleph'.monotone.map_max +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem aleph'_alephIdx (c : Cardinal) : aleph' c.alephIdx = c := Cardinal.alephIdx.relIso.toEquiv.symm_apply_apply c +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-08-28")] theorem alephIdx_aleph' (o : Ordinal) : (aleph' o).alephIdx = o := Cardinal.alephIdx.relIso.toEquiv.apply_symm_apply o +set_option linter.deprecated false in @[deprecated preAleph_zero (since := "2024-10-22")] theorem aleph'_zero : aleph' 0 = 0 := aleph'.map_bot +set_option linter.deprecated false in @[deprecated preAleph_succ (since := "2024-10-22")] theorem aleph'_succ (o : Ordinal) : aleph' (succ o) = succ (aleph' o) := aleph'.map_succ o +set_option linter.deprecated false in @[deprecated preAleph_nat (since := "2024-10-22")] theorem aleph'_nat : ∀ n : ℕ, aleph' n = n := preAleph_nat +set_option linter.deprecated false in @[deprecated lift_preAleph (since := "2024-10-22")] theorem lift_aleph' (o : Ordinal.{u}) : lift.{v} (aleph' o) = aleph' (Ordinal.lift.{v} o) := lift_preAleph o +set_option linter.deprecated false in @[deprecated preAleph_le_of_isLimit (since := "2024-10-22")] theorem aleph'_le_of_limit {o : Ordinal} (l : o.IsLimit) {c} : aleph' o ≤ c ↔ ∀ o' < o, aleph' o' ≤ c := preAleph_le_of_isLimit l +set_option linter.deprecated false in @[deprecated preAleph_limit (since := "2024-10-22")] theorem aleph'_limit {o : Ordinal} (ho : o.IsLimit) : aleph' o = ⨆ a : Iio o, aleph' a := preAleph_limit ho +set_option linter.deprecated false in @[deprecated preAleph_omega0 (since := "2024-10-22")] theorem aleph'_omega0 : aleph' ω = ℵ₀ := preAleph_omega0 @@ -611,6 +628,7 @@ theorem aleph'_omega0 : aleph' ω = ℵ₀ := @[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias aleph'_omega := aleph'_omega0 +set_option linter.deprecated false in /-- `aleph'` and `aleph_idx` form an equivalence between `Ordinal` and `Cardinal` -/ @[deprecated aleph' (since := "2024-08-28")] def aleph'Equiv : Ordinal ≃ Cardinal := @@ -620,14 +638,17 @@ def aleph'Equiv : Ordinal ≃ Cardinal := theorem aleph_eq_aleph' (o : Ordinal) : ℵ_ o = preAleph (ω + o) := rfl +set_option linter.deprecated false in @[deprecated aleph0_le_preAleph (since := "2024-10-22")] theorem aleph0_le_aleph' {o : Ordinal} : ℵ₀ ≤ aleph' o ↔ ω ≤ o := by rw [← aleph'_omega0, aleph'_le] +set_option linter.deprecated false in @[deprecated preAleph_pos (since := "2024-10-22")] theorem aleph'_pos {o : Ordinal} (ho : 0 < o) : 0 < aleph' o := by rwa [← aleph'_zero, aleph'_lt] +set_option linter.deprecated false in @[deprecated preAleph_isNormal (since := "2024-10-22")] theorem aleph'_isNormal : IsNormal (ord ∘ aleph') := preAleph_isNormal @@ -646,15 +667,18 @@ theorem ord_card_unbounded : Unbounded (· < ·) { b : Ordinal | b.card.ord = b dsimp rw [card_ord], (lt_ord_succ_card a).le⟩⟩ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem eq_aleph'_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) : ∃ a, (aleph' a).ord = o := ⟨aleph'.symm o.card, by simpa using ho⟩ +set_option linter.deprecated false in /-- Infinite ordinals that are cardinals are unbounded. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem ord_card_unbounded' : Unbounded (· < ·) { b : Ordinal | b.card.ord = b ∧ ω ≤ b } := (unbounded_lt_inter_le ω).2 ord_card_unbounded +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-24")] theorem eq_aleph_of_eq_card_ord {o : Ordinal} (ho : o.card.ord = o) (ho' : ω ≤ o) : ∃ a, (ℵ_ a).ord = o := by diff --git a/Mathlib/SetTheory/Cardinal/Arithmetic.lean b/Mathlib/SetTheory/Cardinal/Arithmetic.lean index 0c071383f0154..8e9e3236e07e2 100644 --- a/Mathlib/SetTheory/Cardinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Cardinal/Arithmetic.lean @@ -82,7 +82,7 @@ theorem mul_eq_self {c : Cardinal} (h : ℵ₀ ≤ c) : c * c = c := by · exact (mul_lt_aleph0 qo qo).trans_le ol · suffices (succ (typein LT.lt (g p))).card < #α from (IH _ this qo).trans_lt this rw [← lt_ord] - apply (isLimit_ord ol).2 + apply (isLimit_ord ol).succ_lt rw [e] apply typein_lt_type diff --git a/Mathlib/SetTheory/Cardinal/Basic.lean b/Mathlib/SetTheory/Cardinal/Basic.lean index e0105b3587892..12ba9cbde683e 100644 --- a/Mathlib/SetTheory/Cardinal/Basic.lean +++ b/Mathlib/SetTheory/Cardinal/Basic.lean @@ -3,7 +3,6 @@ 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, Floris van Doorn -/ -import Mathlib.Algebra.Order.Ring.Nat import Mathlib.Data.Fintype.BigOperators import Mathlib.Data.Fintype.Powerset import Mathlib.Data.Nat.Cast.Order.Basic @@ -15,6 +14,8 @@ import Mathlib.Order.ConditionallyCompleteLattice.Indexed import Mathlib.Order.InitialSeg import Mathlib.Order.SuccPred.CompleteLinearOrder import Mathlib.SetTheory.Cardinal.SchroederBernstein +import Mathlib.Algebra.Order.GroupWithZero.Canonical +import Mathlib.Algebra.Order.Ring.Canonical /-! # Cardinal Numbers @@ -176,54 +177,6 @@ def map₂ (f : Type u → Type v → Type w) (hf : ∀ α β γ δ, α ≃ β Cardinal.{u} → Cardinal.{v} → Cardinal.{w} := Quotient.map₂ f fun α β ⟨e₁⟩ γ δ ⟨e₂⟩ => ⟨hf α β γ δ e₁ e₂⟩ -/-- We define the order on cardinal numbers by `#α ≤ #β` if and only if - there exists an embedding (injective function) from α to β. -/ -instance : LE Cardinal.{u} := - ⟨fun q₁ q₂ => - Quotient.liftOn₂ q₁ q₂ (fun α β => Nonempty <| α ↪ β) fun _ _ _ _ ⟨e₁⟩ ⟨e₂⟩ => - propext ⟨fun ⟨e⟩ => ⟨e.congr e₁ e₂⟩, fun ⟨e⟩ => ⟨e.congr e₁.symm e₂.symm⟩⟩⟩ - -instance partialOrder : PartialOrder Cardinal.{u} where - le := (· ≤ ·) - le_refl := by - rintro ⟨α⟩ - exact ⟨Embedding.refl _⟩ - le_trans := by - rintro ⟨α⟩ ⟨β⟩ ⟨γ⟩ ⟨e₁⟩ ⟨e₂⟩ - exact ⟨e₁.trans e₂⟩ - le_antisymm := by - rintro ⟨α⟩ ⟨β⟩ ⟨e₁⟩ ⟨e₂⟩ - exact Quotient.sound (e₁.antisymm e₂) - -instance linearOrder : LinearOrder Cardinal.{u} := - { Cardinal.partialOrder with - le_total := by - rintro ⟨α⟩ ⟨β⟩ - apply Embedding.total - decidableLE := Classical.decRel _ } - -theorem le_def (α β : Type u) : #α ≤ #β ↔ Nonempty (α ↪ β) := - Iff.rfl - -theorem mk_le_of_injective {α β : Type u} {f : α → β} (hf : Injective f) : #α ≤ #β := - ⟨⟨f, hf⟩⟩ - -theorem _root_.Function.Embedding.cardinal_le {α β : Type u} (f : α ↪ β) : #α ≤ #β := - ⟨f⟩ - -theorem mk_le_of_surjective {α β : Type u} {f : α → β} (hf : Surjective f) : #β ≤ #α := - ⟨Embedding.ofSurjective f hf⟩ - -theorem le_mk_iff_exists_set {c : Cardinal} {α : Type u} : c ≤ #α ↔ ∃ p : Set α, #p = c := - ⟨inductionOn c fun _ ⟨⟨f, hf⟩⟩ => ⟨Set.range f, (Equiv.ofInjective f hf).cardinal_eq.symm⟩, - fun ⟨_, e⟩ => e ▸ ⟨⟨Subtype.val, fun _ _ => Subtype.eq⟩⟩⟩ - -theorem mk_subtype_le {α : Type u} (p : α → Prop) : #(Subtype p) ≤ #α := - ⟨Embedding.subtype p⟩ - -theorem mk_set_le (s : Set α) : #s ≤ #α := - mk_subtype_le s - /-! ### Lifting cardinals to a higher universe -/ /-- The universe lift operation on cardinals. You can specify the universes explicitly with @@ -280,21 +233,6 @@ lemma mk_preimage_down {s : Set α} : #(ULift.down.{v} ⁻¹' s) = lift.{v} (#s) ULift.up_bijective.comp (restrictPreimage_bijective _ (ULift.down_bijective)) exact Equiv.ofBijective f this -theorem out_embedding {c c' : Cardinal} : c ≤ c' ↔ Nonempty (c.out ↪ c'.out) := by - conv_lhs => rw [← Cardinal.mk_out c, ← Cardinal.mk_out c', le_def] - -theorem lift_mk_le {α : Type v} {β : Type w} : - lift.{max u w} #α ≤ lift.{max u v} #β ↔ Nonempty (α ↪ β) := - ⟨fun ⟨f⟩ => ⟨Embedding.congr Equiv.ulift Equiv.ulift f⟩, fun ⟨f⟩ => - ⟨Embedding.congr Equiv.ulift.symm Equiv.ulift.symm f⟩⟩ - -/-- A variant of `Cardinal.lift_mk_le` with specialized universes. -Because Lean often can not realize it should use this specialization itself, -we provide this statement separately so you don't have to solve the specialization problem either. --/ -theorem lift_mk_le' {α : Type u} {β : Type v} : lift.{v} #α ≤ lift.{u} #β ↔ Nonempty (α ↪ β) := - lift_mk_le.{0} - theorem lift_mk_eq {α : Type u} {β : Type v} : lift.{max v w} #α = lift.{max u w} #β ↔ Nonempty (α ≃ β) := Quotient.eq'.trans @@ -324,6 +262,73 @@ theorem lift_mk_shrink'' (α : Type max u v) [Small.{v} α] : Cardinal.lift.{u} #(Shrink.{v} α) = #α := by rw [← lift_umax, lift_mk_shrink.{max u v, v, 0} α, ← lift_umax, lift_id] +/-! ### Order on cardinals -/ + +/-- We define the order on cardinal numbers by `#α ≤ #β` if and only if + there exists an embedding (injective function) from α to β. -/ +instance : LE Cardinal.{u} := + ⟨fun q₁ q₂ => + Quotient.liftOn₂ q₁ q₂ (fun α β => Nonempty <| α ↪ β) fun _ _ _ _ ⟨e₁⟩ ⟨e₂⟩ => + propext ⟨fun ⟨e⟩ => ⟨e.congr e₁ e₂⟩, fun ⟨e⟩ => ⟨e.congr e₁.symm e₂.symm⟩⟩⟩ + +instance partialOrder : PartialOrder Cardinal.{u} where + le := (· ≤ ·) + le_refl := by + rintro ⟨α⟩ + exact ⟨Embedding.refl _⟩ + le_trans := by + rintro ⟨α⟩ ⟨β⟩ ⟨γ⟩ ⟨e₁⟩ ⟨e₂⟩ + exact ⟨e₁.trans e₂⟩ + le_antisymm := by + rintro ⟨α⟩ ⟨β⟩ ⟨e₁⟩ ⟨e₂⟩ + exact Quotient.sound (e₁.antisymm e₂) + +instance linearOrder : LinearOrder Cardinal.{u} := + { Cardinal.partialOrder with + le_total := by + rintro ⟨α⟩ ⟨β⟩ + apply Embedding.total + decidableLE := Classical.decRel _ } + +theorem le_def (α β : Type u) : #α ≤ #β ↔ Nonempty (α ↪ β) := + Iff.rfl + +theorem mk_le_of_injective {α β : Type u} {f : α → β} (hf : Injective f) : #α ≤ #β := + ⟨⟨f, hf⟩⟩ + +theorem _root_.Function.Embedding.cardinal_le {α β : Type u} (f : α ↪ β) : #α ≤ #β := + ⟨f⟩ + +theorem mk_le_of_surjective {α β : Type u} {f : α → β} (hf : Surjective f) : #β ≤ #α := + ⟨Embedding.ofSurjective f hf⟩ + +theorem le_mk_iff_exists_set {c : Cardinal} {α : Type u} : c ≤ #α ↔ ∃ p : Set α, #p = c := + ⟨inductionOn c fun _ ⟨⟨f, hf⟩⟩ => ⟨Set.range f, (Equiv.ofInjective f hf).cardinal_eq.symm⟩, + fun ⟨_, e⟩ => e ▸ ⟨⟨Subtype.val, fun _ _ => Subtype.eq⟩⟩⟩ + +theorem mk_subtype_le {α : Type u} (p : α → Prop) : #(Subtype p) ≤ #α := + ⟨Embedding.subtype p⟩ + +theorem mk_set_le (s : Set α) : #s ≤ #α := + mk_subtype_le s + +theorem out_embedding {c c' : Cardinal} : c ≤ c' ↔ Nonempty (c.out ↪ c'.out) := by + conv_lhs => rw [← Cardinal.mk_out c, ← Cardinal.mk_out c', le_def] + +theorem lift_mk_le {α : Type v} {β : Type w} : + lift.{max u w} #α ≤ lift.{max u v} #β ↔ Nonempty (α ↪ β) := + ⟨fun ⟨f⟩ => ⟨Embedding.congr Equiv.ulift Equiv.ulift f⟩, fun ⟨f⟩ => + ⟨Embedding.congr Equiv.ulift.symm Equiv.ulift.symm f⟩⟩ + +/-- A variant of `Cardinal.lift_mk_le` with specialized universes. +Because Lean often can not realize it should use this specialization itself, +we provide this statement separately so you don't have to solve the specialization problem either. +-/ +theorem lift_mk_le' {α : Type u} {β : Type v} : lift.{v} #α ≤ lift.{u} #β ↔ Nonempty (α ↪ β) := + lift_mk_le.{0} + +/-! ### `lift` sends `Cardinal.{u}` to an initial segment of `Cardinal.{max u v}`. -/ + /-- `Cardinal.lift` as an `InitialSeg`. -/ @[simps!] def liftInitialSeg : Cardinal.{u} ≤i Cardinal.{max u v} := by @@ -814,19 +819,21 @@ protected theorem isSuccLimit_iff {c : Cardinal} : IsSuccLimit c ↔ c ≠ 0 ∧ section deprecated -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated IsSuccLimit.isSuccPrelimit (since := "2024-09-17")] protected theorem IsLimit.isSuccPrelimit {c} (h : IsLimit c) : IsSuccPrelimit c := h.2 +set_option linter.deprecated false in @[deprecated ne_zero_of_isSuccLimit (since := "2024-09-17")] protected theorem IsLimit.ne_zero {c} (h : IsLimit c) : c ≠ 0 := h.1 +set_option linter.deprecated false in @[deprecated IsLimit.isSuccPrelimit (since := "2024-09-05")] alias IsLimit.isSuccLimit := IsLimit.isSuccPrelimit +set_option linter.deprecated false in @[deprecated IsSuccLimit.succ_lt (since := "2024-09-17")] theorem IsLimit.succ_lt {x c} (h : IsLimit c) : x < c → succ x < c := h.isSuccPrelimit.succ_lt @@ -1518,17 +1525,18 @@ theorem aleph0_le_of_isSuccLimit {c : Cardinal} (h : IsSuccLimit c) : ℵ₀ ≤ section deprecated -set_option linter.deprecated false - +set_option linter.deprecated false in @[deprecated isSuccLimit_aleph0 (since := "2024-09-17")] theorem isLimit_aleph0 : IsLimit ℵ₀ := ⟨aleph0_ne_zero, isSuccPrelimit_aleph0⟩ +set_option linter.deprecated false in @[deprecated not_isSuccLimit_natCast (since := "2024-09-17")] lemma not_isLimit_natCast : (n : ℕ) → ¬ IsLimit (n : Cardinal.{u}) | 0, e => e.1 rfl | Nat.succ n, e => Order.not_isSuccPrelimit_succ _ (nat_succ n ▸ e.2) +set_option linter.deprecated false in @[deprecated aleph0_le_of_isSuccLimit (since := "2024-09-17")] theorem IsLimit.aleph0_le {c : Cardinal} (h : IsLimit c) : ℵ₀ ≤ c := by by_contra! h' @@ -1778,12 +1786,12 @@ theorem mk_plift_false : #(PLift False) = 0 := mk_eq_zero _ @[simp] -theorem mk_vector (α : Type u) (n : ℕ) : #(Vector α n) = #α ^ n := +theorem mk_vector (α : Type u) (n : ℕ) : #(Mathlib.Vector α n) = #α ^ n := (mk_congr (Equiv.vectorEquivFin α n)).trans <| by simp theorem mk_list_eq_sum_pow (α : Type u) : #(List α) = sum fun n : ℕ => #α ^ n := calc - #(List α) = #(Σn, Vector α n) := mk_congr (Equiv.sigmaFiberEquiv List.length).symm + #(List α) = #(Σn, Mathlib.Vector α n) := mk_congr (Equiv.sigmaFiberEquiv List.length).symm _ = sum fun n : ℕ => #α ^ n := by simp theorem mk_quot_le {α : Type u} {r : α → α → Prop} : #(Quot r) ≤ #α := diff --git a/Mathlib/SetTheory/Cardinal/Cofinality.lean b/Mathlib/SetTheory/Cardinal/Cofinality.lean index 9a8363e186c9a..786a594aa7434 100644 --- a/Mathlib/SetTheory/Cardinal/Cofinality.lean +++ b/Mathlib/SetTheory/Cardinal/Cofinality.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, Floris van Doorn, Violeta Hernández Palacios -/ +import Mathlib.Data.Set.Finite.Lattice import Mathlib.SetTheory.Cardinal.Arithmetic import Mathlib.SetTheory.Ordinal.FixedPoint @@ -695,7 +696,7 @@ theorem cof_eq' (r : α → α → Prop) [IsWellOrder α r] (h : IsLimit (type r ∃ S : Set α, (∀ a, ∃ b ∈ S, r a b) ∧ #S = cof (type r) := let ⟨S, H, e⟩ := cof_eq r ⟨S, fun a => - let a' := enum r ⟨_, h.2 _ (typein_lt_type r a)⟩ + let a' := enum r ⟨_, h.succ_lt (typein_lt_type r a)⟩ let ⟨b, h, ab⟩ := H a' ⟨b, h, (IsOrderConnected.conn a b a' <| @@ -833,11 +834,13 @@ theorem isStrongLimit_beth {o : Ordinal} (H : IsSuccPrelimit o) : IsStrongLimit · rw [beth_zero] exact isStrongLimit_aleph0 · refine ⟨beth_ne_zero o, fun a ha => ?_⟩ - rw [beth_limit ⟨h, isSuccPrelimit_iff_succ_lt.1 H⟩] at ha - rcases exists_lt_of_lt_ciSup' ha with ⟨⟨i, hi⟩, ha⟩ - have := power_le_power_left two_ne_zero ha.le - rw [← beth_succ] at this - exact this.trans_lt (beth_lt.2 (H.succ_lt hi)) + rw [beth_limit] at ha + · rcases exists_lt_of_lt_ciSup' ha with ⟨⟨i, hi⟩, ha⟩ + have := power_le_power_left two_ne_zero ha.le + rw [← beth_succ] at this + exact this.trans_lt (beth_lt.2 (H.succ_lt hi)) + · rw [isLimit_iff] + exact ⟨h, H⟩ theorem mk_bounded_subset {α : Type*} (h : ∀ x < #α, (2^x) < #α) {r : α → α → Prop} [IsWellOrder α r] (hr : (#α).ord = type r) : #{ s : Set α // Bounded r s } = #α := by @@ -1139,7 +1142,7 @@ theorem derivFamily_lt_ord_lift {ι : Type u} {f : ι → Ordinal → Ordinal} { rw [derivFamily_succ] exact nfpFamily_lt_ord_lift hω (by rwa [hc.cof_eq]) hf - ((isLimit_ord hc.1).2 _ (hb ((lt_succ b).trans hb'))) + ((isLimit_ord hc.1).succ_lt (hb ((lt_succ b).trans hb'))) | H₃ b hb H => intro hb' -- TODO: generalize the universes of the lemmas in this file so we don't have to rely on bsup diff --git a/Mathlib/SetTheory/Cardinal/Continuum.lean b/Mathlib/SetTheory/Cardinal/Continuum.lean index b05977809225d..fd2ba0a5e9087 100644 --- a/Mathlib/SetTheory/Cardinal/Continuum.lean +++ b/Mathlib/SetTheory/Cardinal/Continuum.lean @@ -87,8 +87,8 @@ theorem continuum_toNat : toNat continuum = 0 := toNat_apply_of_aleph0_le aleph0_le_continuum @[simp] -theorem continuum_toPartENat : toPartENat continuum = ⊤ := - toPartENat_apply_of_aleph0_le aleph0_le_continuum +theorem continuum_toENat : toENat continuum = ⊤ := + (toENat_eq_top.2 aleph0_le_continuum) /-! ### Addition diff --git a/Mathlib/SetTheory/Cardinal/ENat.lean b/Mathlib/SetTheory/Cardinal/ENat.lean index 07957687d320d..b444b8fb5cd1f 100644 --- a/Mathlib/SetTheory/Cardinal/ENat.lean +++ b/Mathlib/SetTheory/Cardinal/ENat.lean @@ -260,6 +260,23 @@ theorem toENat_lift {a : Cardinal.{v}} : toENat (lift.{u} a) = toENat a := by | inl ha => lift a to ℕ∞ using ha; simp | inr ha => simp [toENat_eq_top.2, ha] +theorem toENat_congr {α : Type u} {β : Type v} (e : α ≃ β) : toENat #α = toENat #β := by + rw [← toENat_lift, lift_mk_eq.{_, _,v}.mpr ⟨e⟩, toENat_lift] + +lemma toENat_le_iff_of_le_aleph0 {c c' : Cardinal} (h : c ≤ ℵ₀) : + toENat c ≤ toENat c' ↔ c ≤ c' := by + lift c to ℕ∞ using h + simp_rw [toENat_ofENat, enat_gc _] + +lemma toENat_le_iff_of_lt_aleph0 {c c' : Cardinal} (hc' : c' < ℵ₀) : + toENat c ≤ toENat c' ↔ c ≤ c' := by + lift c' to ℕ using hc' + simp_rw [toENat_nat, ← toENat_le_nat] + +lemma toENat_eq_iff_of_le_aleph0 {c c' : Cardinal} (hc : c ≤ ℵ₀) (hc' : c' ≤ ℵ₀) : + toENat c = toENat c' ↔ c = c' := + toENat_strictMonoOn.injOn.eq_iff hc hc' + @[simp, norm_cast] lemma ofENat_add (m n : ℕ∞) : ofENat (m + n) = m + n := by apply toENat_injOn <;> simp @@ -288,4 +305,6 @@ def ofENatHom : ℕ∞ →+*o Cardinal where map_add' := ofENat_add monotone' := ofENat_mono + + end Cardinal diff --git a/Mathlib/SetTheory/Cardinal/Finite.lean b/Mathlib/SetTheory/Cardinal/Finite.lean index e31452e7c7598..ed8bad925692c 100644 --- a/Mathlib/SetTheory/Cardinal/Finite.lean +++ b/Mathlib/SetTheory/Cardinal/Finite.lean @@ -5,7 +5,8 @@ Authors: Aaron Anderson -/ import Mathlib.Data.ULift import Mathlib.Data.ZMod.Defs -import Mathlib.SetTheory.Cardinal.PartENat +import Mathlib.SetTheory.Cardinal.ToNat +import Mathlib.SetTheory.Cardinal.ENat /-! # Finite Cardinality Functions @@ -14,8 +15,10 @@ import Mathlib.SetTheory.Cardinal.PartENat * `Nat.card α` is the cardinality of `α` as a natural number. If `α` is infinite, `Nat.card α = 0`. +* `ENat.card α` is the cardinality of `α` as an extended natural number. + If `α` is infinite, `ENat.card α = ⊤`. * `PartENat.card α` is the cardinality of `α` as an extended natural number - (using `Part ℕ`). If `α` is infinite, `PartENat.card α = ⊤`. + (using the legacy definition `PartENat := Part ℕ`). If `α` is infinite, `PartENat.card α = ⊤`. -/ open Cardinal Function @@ -242,89 +245,80 @@ protected alias ⟨_, Nonempty.natCard_pos⟩ := natCard_pos end Set -namespace PartENat -/-- `PartENat.card α` is the cardinality of `α` as an extended natural number. - If `α` is infinite, `PartENat.card α = ⊤`. -/ -def card (α : Type*) : PartENat := - toPartENat (mk α) +namespace ENat + +/-- `ENat.card α` is the cardinality of `α` as an extended natural number. + If `α` is infinite, `ENat.card α = ⊤`. -/ +def card (α : Type*) : ℕ∞ := + toENat (mk α) @[simp] -theorem card_eq_coe_fintype_card [Fintype α] : card α = Fintype.card α := - mk_toPartENat_eq_coe_card +theorem card_eq_coe_fintype_card [Fintype α] : card α = Fintype.card α := by + simp [card] @[simp] -theorem card_eq_top_of_infinite [Infinite α] : card α = ⊤ := - mk_toPartENat_of_infinite +theorem card_eq_top_of_infinite [Infinite α] : card α = ⊤ := by + simp [card] @[simp] theorem card_sum (α β : Type*) : - PartENat.card (α ⊕ β) = PartENat.card α + PartENat.card β := by - simp only [PartENat.card, Cardinal.mk_sum, map_add, Cardinal.toPartENat_lift] + card (α ⊕ β) = card α + card β := by + simp only [card, mk_sum, map_add, toENat_lift] -theorem card_congr {α : Type*} {β : Type*} (f : α ≃ β) : PartENat.card α = PartENat.card β := - Cardinal.toPartENat_congr f +theorem card_congr {α β : Type*} (f : α ≃ β) : card α = card β := + Cardinal.toENat_congr f @[simp] lemma card_ulift (α : Type*) : card (ULift α) = card α := card_congr Equiv.ulift @[simp] lemma card_plift (α : Type*) : card (PLift α) = card α := card_congr Equiv.plift -theorem card_image_of_injOn {α : Type u} {β : Type v} {f : α → β} {s : Set α} (h : Set.InjOn f s) : +theorem card_image_of_injOn {α β : Type*} {f : α → β} {s : Set α} (h : Set.InjOn f s) : card (f '' s) = card s := card_congr (Equiv.Set.imageOfInjOn f s h).symm -theorem card_image_of_injective {α : Type u} {β : Type v} (f : α → β) (s : Set α) +theorem card_image_of_injective {α β : Type*} (f : α → β) (s : Set α) (h : Function.Injective f) : card (f '' s) = card s := card_image_of_injOn h.injOn --- Should I keep the 6 following lemmas ? --- TODO: Add ofNat, zero, and one versions for simp confluence @[simp] -theorem _root_.Cardinal.natCast_le_toPartENat_iff {n : ℕ} {c : Cardinal} : - ↑n ≤ toPartENat c ↔ ↑n ≤ c := by - rw [← toPartENat_natCast n, toPartENat_le_iff_of_le_aleph0 (le_of_lt (nat_lt_aleph0 n))] +theorem _root_.Cardinal.natCast_le_toENat_iff {n : ℕ} {c : Cardinal} : + ↑n ≤ toENat c ↔ ↑n ≤ c := by + rw [← toENat_nat n, toENat_le_iff_of_le_aleph0 (le_of_lt (nat_lt_aleph0 n))] -@[simp] -theorem _root_.Cardinal.toPartENat_le_natCast_iff {c : Cardinal} {n : ℕ} : - toPartENat c ≤ n ↔ c ≤ n := by - rw [← toPartENat_natCast n, toPartENat_le_iff_of_lt_aleph0 (nat_lt_aleph0 n)] +theorem _root_.Cardinal.toENat_le_natCast_iff {c : Cardinal} {n : ℕ} : + toENat c ≤ n ↔ c ≤ n := by simp @[simp] -theorem _root_.Cardinal.natCast_eq_toPartENat_iff {n : ℕ} {c : Cardinal} : - ↑n = toPartENat c ↔ ↑n = c := by - rw [le_antisymm_iff, le_antisymm_iff, Cardinal.toPartENat_le_natCast_iff, - Cardinal.natCast_le_toPartENat_iff] +theorem _root_.Cardinal.natCast_eq_toENat_iff {n : ℕ} {c : Cardinal} : + ↑n = toENat c ↔ ↑n = c := by + rw [le_antisymm_iff, le_antisymm_iff, Cardinal.toENat_le_natCast_iff, + Cardinal.natCast_le_toENat_iff] -@[simp] -theorem _root_.Cardinal.toPartENat_eq_natCast_iff {c : Cardinal} {n : ℕ} : - Cardinal.toPartENat c = n ↔ c = n := by -rw [eq_comm, Cardinal.natCast_eq_toPartENat_iff, eq_comm] +theorem _root_.Cardinal.toENat_eq_natCast_iff {c : Cardinal} {n : ℕ} : + Cardinal.toENat c = n ↔ c = n := by simp @[simp] -theorem _root_.Cardinal.natCast_lt_toPartENat_iff {n : ℕ} {c : Cardinal} : - ↑n < toPartENat c ↔ ↑n < c := by - simp only [← not_le, Cardinal.toPartENat_le_natCast_iff] +theorem _root_.Cardinal.natCast_lt_toENat_iff {n : ℕ} {c : Cardinal} : + ↑n < toENat c ↔ ↑n < c := by + simp only [← not_le, Cardinal.toENat_le_natCast_iff] @[simp] -theorem _root_.Cardinal.toPartENat_lt_natCast_iff {n : ℕ} {c : Cardinal} : - toPartENat c < ↑n ↔ c < ↑n := by - simp only [← not_le, Cardinal.natCast_le_toPartENat_iff] +theorem _root_.Cardinal.toENat_lt_natCast_iff {n : ℕ} {c : Cardinal} : + toENat c < ↑n ↔ c < ↑n := by + simp only [← not_le, Cardinal.natCast_le_toENat_iff] theorem card_eq_zero_iff_empty (α : Type*) : card α = 0 ↔ IsEmpty α := by rw [← Cardinal.mk_eq_zero_iff] - conv_rhs => rw [← Nat.cast_zero] - simp only [← Cardinal.toPartENat_eq_natCast_iff] - simp only [PartENat.card, Nat.cast_zero] + simp [card] theorem card_le_one_iff_subsingleton (α : Type*) : card α ≤ 1 ↔ Subsingleton α := by rw [← le_one_iff_subsingleton] - conv_rhs => rw [← Nat.cast_one] - rw [← Cardinal.toPartENat_le_natCast_iff] - simp only [PartENat.card, Nat.cast_one] + simp [card] theorem one_lt_card_iff_nontrivial (α : Type*) : 1 < card α ↔ Nontrivial α := by rw [← Cardinal.one_lt_iff_nontrivial] conv_rhs => rw [← Nat.cast_one] - rw [← natCast_lt_toPartENat_iff] - simp only [PartENat.card, Nat.cast_one] + rw [← natCast_lt_toENat_iff] + simp only [ENat.card, Nat.cast_one] -end PartENat +end ENat diff --git a/Mathlib/SetTheory/Game/PGame.lean b/Mathlib/SetTheory/Game/PGame.lean index 63640f6a65f95..d1e221f7c4878 100644 --- a/Mathlib/SetTheory/Game/PGame.lean +++ b/Mathlib/SetTheory/Game/PGame.lean @@ -4,7 +4,6 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Reid Barton, Mario Carneiro, Isabel Longbottom, Kim Morrison, Yuyang Zhao -/ import Mathlib.Algebra.Order.ZeroLEOne -import Mathlib.Data.List.InsertIdx import Mathlib.Logic.Relation import Mathlib.Logic.Small.Defs import Mathlib.Order.GameAdd @@ -393,7 +392,7 @@ theorem moveRight_memᵣ (x : PGame) (b) : x.moveRight b ∈ᵣ x := ⟨_, .rfl theorem identical_of_isEmpty (x y : PGame) [IsEmpty x.LeftMoves] [IsEmpty x.RightMoves] [IsEmpty y.LeftMoves] [IsEmpty y.RightMoves] : x ≡ y := - identical_iff.2 <| by simp [Relator.BiTotal, Relator.LeftTotal, Relator.RightTotal] + identical_iff.2 (by simp [biTotal_empty]) /-- `Identical` as a `Setoid`. -/ def identicalSetoid : Setoid PGame := diff --git a/Mathlib/SetTheory/Ordinal/Arithmetic.lean b/Mathlib/SetTheory/Ordinal/Arithmetic.lean index 3563908538d09..bd4d0884f8560 100644 --- a/Mathlib/SetTheory/Ordinal/Arithmetic.lean +++ b/Mathlib/SetTheory/Ordinal/Arithmetic.lean @@ -3,10 +3,11 @@ Copyright (c) 2017 Johannes Hölzl. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mario Carneiro, Floris van Doorn, Violeta Hernández Palacios -/ -import Mathlib.SetTheory.Ordinal.Basic -import Mathlib.Data.Nat.SuccPred import Mathlib.Algebra.GroupWithZero.Divisibility +import Mathlib.Data.Nat.SuccPred +import Mathlib.Order.SuccPred.InitialSeg import Mathlib.SetTheory.Cardinal.UnivLE +import Mathlib.SetTheory.Ordinal.Basic /-! # Ordinal arithmetic @@ -197,33 +198,36 @@ theorem lift_pred (o : Ordinal.{v}) : lift.{u} (pred o) = pred (lift.{u} o) := b TODO: deprecate this in favor of `Order.IsSuccLimit`. -/ def IsLimit (o : Ordinal) : Prop := - o ≠ 0 ∧ ∀ a < o, succ a < o + IsSuccLimit o + +theorem isLimit_iff {o} : IsLimit o ↔ o ≠ 0 ∧ IsSuccPrelimit o := by + simp [IsLimit, IsSuccLimit] theorem IsLimit.isSuccPrelimit {o} (h : IsLimit o) : IsSuccPrelimit o := - isSuccPrelimit_iff_succ_lt.mpr h.2 + IsSuccLimit.isSuccPrelimit h @[deprecated IsLimit.isSuccPrelimit (since := "2024-09-05")] alias IsLimit.isSuccLimit := IsLimit.isSuccPrelimit theorem IsLimit.succ_lt {o a : Ordinal} (h : IsLimit o) : a < o → succ a < o := - h.2 a + IsSuccLimit.succ_lt h theorem isSuccPrelimit_zero : IsSuccPrelimit (0 : Ordinal) := isSuccPrelimit_bot @[deprecated isSuccPrelimit_zero (since := "2024-09-05")] alias isSuccLimit_zero := isSuccPrelimit_zero -theorem not_zero_isLimit : ¬IsLimit 0 - | ⟨h, _⟩ => h rfl +theorem not_zero_isLimit : ¬IsLimit 0 := + not_isSuccLimit_bot -theorem not_succ_isLimit (o) : ¬IsLimit (succ o) - | ⟨_, h⟩ => lt_irrefl _ (h _ (lt_succ o)) +theorem not_succ_isLimit (o) : ¬IsLimit (succ o) := + not_isSuccLimit_succ o theorem not_succ_of_isLimit {o} (h : IsLimit o) : ¬∃ a, o = succ a | ⟨a, e⟩ => not_succ_isLimit a (e ▸ h) theorem succ_lt_of_isLimit {o a : Ordinal} (h : IsLimit o) : succ a < o ↔ a < o := - ⟨(lt_succ a).trans, h.2 _⟩ + IsSuccLimit.succ_lt_iff h theorem le_succ_of_isLimit {o} (h : IsLimit o) {a} : o ≤ succ a ↔ o ≤ a := le_iff_le_iff_lt_iff_lt.2 <| succ_lt_of_isLimit h @@ -238,29 +242,23 @@ theorem lt_limit {o} (h : IsLimit o) {a} : a < o ↔ ∃ x < o, a < x := by @[simp] theorem lift_isLimit (o : Ordinal.{v}) : IsLimit (lift.{u,v} o) ↔ IsLimit o := - and_congr (not_congr <| by simpa only [lift_zero] using @lift_inj o 0) - ⟨fun H a h => (lift_lt.{u,v}).1 <| - by simpa only [lift_succ] using H _ (lift_lt.2 h), fun H a h => by - obtain ⟨a', rfl⟩ := mem_range_lift_of_le h.le - rw [← lift_succ, lift_lt] - exact H a' (lift_lt.1 h)⟩ + liftInitialSeg.isSuccLimit_apply_iff theorem IsLimit.pos {o : Ordinal} (h : IsLimit o) : 0 < o := - lt_of_le_of_ne (Ordinal.zero_le _) h.1.symm + IsSuccLimit.bot_lt h + +theorem IsLimit.ne_zero {o : Ordinal} (h : IsLimit o) : o ≠ 0 := + h.pos.ne' theorem IsLimit.one_lt {o : Ordinal} (h : IsLimit o) : 1 < o := by - simpa only [succ_zero] using h.2 _ h.pos + simpa only [succ_zero] using h.succ_lt h.pos theorem IsLimit.nat_lt {o : Ordinal} (h : IsLimit o) : ∀ n : ℕ, (n : Ordinal) < o | 0 => h.pos - | n + 1 => h.2 _ (IsLimit.nat_lt h n) + | n + 1 => h.succ_lt (IsLimit.nat_lt h n) theorem zero_or_succ_or_limit (o : Ordinal) : o = 0 ∨ (∃ a, o = succ a) ∨ IsLimit o := by - classical - exact if o0 : o = 0 then Or.inl o0 - else - if h : ∃ a, o = succ a then Or.inr (Or.inl h) - else Or.inr <| Or.inr ⟨o0, fun _a => (succ_lt_of_not_succ h).2⟩ + simpa [eq_comm] using isMin_or_mem_range_succ_or_isSuccLimit o theorem isLimit_of_not_succ_of_ne_zero {o : Ordinal} (h : ¬∃ a, o = succ a) (h' : o ≠ 0) : IsLimit o := ((zero_or_succ_or_limit o).resolve_left h').resolve_left h @@ -279,23 +277,24 @@ theorem IsLimit.iSup_Iio {o : Ordinal} (h : IsLimit o) : ⨆ a : Iio o, a.1 = o induction at successor ordinals and at limit ordinals, then it holds for all ordinals. -/ @[elab_as_elim] def limitRecOn {C : Ordinal → Sort*} (o : Ordinal) (H₁ : C 0) (H₂ : ∀ o, C o → C (succ o)) - (H₃ : ∀ o, IsLimit o → (∀ o' < o, C o') → C o) : C o := - SuccOrder.prelimitRecOn o (fun o _ ↦ H₂ o) fun o hl ↦ - if h : o = 0 then fun _ ↦ h ▸ H₁ else H₃ o ⟨h, fun _ ↦ hl.succ_lt⟩ + (H₃ : ∀ o, IsLimit o → (∀ o' < o, C o') → C o) : C o := by + refine SuccOrder.limitRecOn o (fun a ha ↦ ?_) (fun a _ ↦ H₂ a) H₃ + convert H₁ + simpa using ha @[simp] -theorem limitRecOn_zero {C} (H₁ H₂ H₃) : @limitRecOn C 0 H₁ H₂ H₃ = H₁ := by - rw [limitRecOn, SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ isSuccPrelimit_zero, dif_pos rfl] +theorem limitRecOn_zero {C} (H₁ H₂ H₃) : @limitRecOn C 0 H₁ H₂ H₃ = H₁ := + SuccOrder.limitRecOn_isMin _ _ _ isMin_bot @[simp] theorem limitRecOn_succ {C} (o H₁ H₂ H₃) : - @limitRecOn C (succ o) H₁ H₂ H₃ = H₂ o (@limitRecOn C o H₁ H₂ H₃) := by - rw [limitRecOn, limitRecOn, SuccOrder.prelimitRecOn_succ] + @limitRecOn C (succ o) H₁ H₂ H₃ = H₂ o (@limitRecOn C o H₁ H₂ H₃) := + SuccOrder.limitRecOn_succ .. @[simp] theorem limitRecOn_limit {C} (o H₁ H₂ H₃ h) : - @limitRecOn C o H₁ H₂ H₃ = H₃ o h fun x _h => @limitRecOn C x H₁ H₂ H₃ := by - simp_rw [limitRecOn, SuccOrder.prelimitRecOn_of_isSuccPrelimit _ _ h.isSuccPrelimit, dif_neg h.1] + @limitRecOn C o H₁ H₂ H₃ = H₃ o h fun x _h => @limitRecOn C x H₁ H₂ H₃ := + SuccOrder.limitRecOn_of_isSuccLimit .. /-- Bounded recursion on ordinals. Similar to `limitRecOn`, with the assumption `o < l` added to all cases. The final term's domain is the ordinals below `l`. -/ @@ -347,7 +346,7 @@ alias out_no_max_of_succ_lt := toType_noMax_of_succ_lt theorem bounded_singleton {r : α → α → Prop} [IsWellOrder α r] (hr : (type r).IsLimit) (x) : Bounded r {x} := by - refine ⟨enum r ⟨succ (typein r x), hr.2 _ (typein_lt_type r x)⟩, ?_⟩ + refine ⟨enum r ⟨succ (typein r x), hr.succ_lt (typein_lt_type r x)⟩, ?_⟩ intro b hb rw [mem_singleton_iff.1 hb] nth_rw 1 [← enum_typein r x] @@ -398,7 +397,7 @@ theorem IsNormal.strictMono {f} (H : IsNormal f) : StrictMono f := fun a b => limitRecOn b (Not.elim (not_lt_of_le <| Ordinal.zero_le _)) (fun _b IH h => (lt_or_eq_of_le (le_of_lt_succ h)).elim (fun h => (IH h).trans (H.1 _)) fun e => e ▸ H.1 _) - fun _b l _IH h => lt_of_lt_of_le (H.1 a) ((H.2 _ l _).1 le_rfl _ (l.2 _ h)) + fun _b l _IH h => lt_of_lt_of_le (H.1 a) ((H.2 _ l _).1 le_rfl _ (l.succ_lt h)) theorem IsNormal.monotone {f} (H : IsNormal f) : Monotone f := H.strictMono.monotone @@ -460,12 +459,17 @@ theorem IsNormal.trans {f g} (H₁ : IsNormal f) (H₂ : IsNormal g) : IsNormal ⟨fun _x => H₁.lt_iff.2 (H₂.1 _), fun o l _a => H₁.le_set' (· < o) ⟨0, l.pos⟩ g _ fun _c => H₂.2 _ l _⟩ -theorem IsNormal.isLimit {f} (H : IsNormal f) {o} (l : IsLimit o) : IsLimit (f o) := - ⟨ne_of_gt <| (Ordinal.zero_le _).trans_lt <| H.lt_iff.2 l.pos, fun _ h => - let ⟨_b, h₁, h₂⟩ := (H.limit_lt l).1 h - (succ_le_of_lt h₂).trans_lt (H.lt_iff.2 h₁)⟩ +theorem IsNormal.isLimit {f} (H : IsNormal f) {o} (ho : IsLimit o) : IsLimit (f o) := by + rw [isLimit_iff, isSuccPrelimit_iff_succ_lt] + use (H.lt_iff.2 ho.pos).ne_bot + intro a ha + obtain ⟨b, hb, hab⟩ := (H.limit_lt ho).1 ha + rw [← succ_le_iff] at hab + apply hab.trans_lt + rwa [H.lt_iff] -theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a + b ≤ c ↔ ∀ b' < b, a + b' ≤ c := +private theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : + a + b ≤ c ↔ ∀ b' < b, a + b' ≤ c := ⟨fun h _ l => (add_le_add_left l.le _).trans h, fun H => le_of_not_lt <| by -- Porting note: `induction` tactics are required because of the parser bug. @@ -482,7 +486,7 @@ theorem add_le_of_limit {a b c : Ordinal} (h : IsLimit b) : a + b ≤ c ↔ ∀ · exact irrefl _ (this _) intro x rw [← typein_lt_typein (Sum.Lex r s), typein_enum] - have := H _ (h.2 _ (typein_lt_type s x)) + have := H _ (h.succ_lt (typein_lt_type s x)) rw [add_succ, succ_le_iff] at this refine (RelEmbedding.ofMonotone (fun a => ?_) fun a b => ?_).ordinal_type_le.trans_lt this @@ -566,6 +570,9 @@ protected theorem sub_eq_zero_iff_le {a b : Ordinal} : a - b = 0 ↔ a ≤ b := ⟨fun h => by simpa only [h, add_zero] using le_add_sub a b, fun h => by rwa [← Ordinal.le_zero, sub_le, add_zero]⟩ +protected theorem sub_ne_zero_iff_lt {a b : Ordinal} : a - b ≠ 0 ↔ b < a := by + simpa using Ordinal.sub_eq_zero_iff_le.not + theorem sub_sub (a b c : Ordinal) : a - b - c = a - (b + c) := eq_of_forall_ge_iff fun d => by rw [sub_le, sub_le, sub_le, add_assoc] @@ -587,33 +594,23 @@ theorem lt_add_iff {a b c : Ordinal} (hc : c ≠ 0) : a < b + c ↔ ∃ d < c, a rintro ⟨d, hd, ha⟩ exact ha.trans_lt (add_lt_add_left hd b) -theorem isLimit_sub {a b} (l : IsLimit a) (h : b < a) : IsLimit (a - b) := - ⟨ne_of_gt <| lt_sub.2 <| by rwa [add_zero], fun c h => by - rw [lt_sub, add_succ]; exact l.2 _ (lt_sub.1 h)⟩ +theorem add_le_iff {a b c : Ordinal} (hb : b ≠ 0) : a + b ≤ c ↔ ∀ d < b, a + d < c := by + simpa using (lt_add_iff hb).not -@[deprecated isLimit_sub (since := "2024-10-11")] -alias sub_isLimit := isLimit_sub - -theorem one_add_omega0 : 1 + ω = ω := by - refine le_antisymm ?_ (le_add_left _ _) - rw [omega0, ← lift_one.{0}, ← lift_add, lift_le, ← type_unit, ← type_sum_lex] - refine ⟨RelEmbedding.collapse (RelEmbedding.ofMonotone ?_ ?_)⟩ - · apply Sum.rec - · exact fun _ => 0 - · exact Nat.succ - · intro a b - cases a <;> cases b <;> intro H <;> cases' H with _ _ H _ _ H <;> - [exact H.elim; exact Nat.succ_pos _; exact Nat.succ_lt_succ H] - -@[deprecated "No deprecation message was provided." (since := "2024-09-30")] -alias one_add_omega := one_add_omega0 +@[deprecated add_le_iff (since := "2024-12-08")] +theorem add_le_of_forall_add_lt {a b c : Ordinal} (hb : 0 < b) (h : ∀ d < b, a + d < c) : + a + b ≤ c := + (add_le_iff hb.ne').2 h -@[simp] -theorem one_add_of_omega0_le {o} (h : ω ≤ o) : 1 + o = o := by - rw [← Ordinal.add_sub_cancel_of_le h, ← add_assoc, one_add_omega0] +theorem isLimit_sub {a b} (ha : IsLimit a) (h : b < a) : IsLimit (a - b) := by + rw [isLimit_iff, Ordinal.sub_ne_zero_iff_lt, isSuccPrelimit_iff_succ_lt] + refine ⟨h, fun c hc ↦ ?_⟩ + rw [lt_sub] at hc ⊢ + rw [add_succ] + exact ha.succ_lt hc -@[deprecated "No deprecation message was provided." (since := "2024-09-30")] -alias one_add_of_omega_le := one_add_of_omega0_le +@[deprecated isLimit_sub (since := "2024-10-11")] +alias sub_isLimit := isLimit_sub /-! ### Multiplication of ordinals -/ @@ -732,7 +729,7 @@ private theorem mul_le_of_limit_aux {α β r s} [IsWellOrder α r] [IsWellOrder exact irrefl _ (this _ _) intro a b rw [← typein_lt_typein (Prod.Lex s r), typein_enum] - have := H _ (h.2 _ (typein_lt_type s b)) + have := H _ (h.succ_lt (typein_lt_type s b)) rw [mul_succ] at this have := ((add_lt_add_iff_left _).2 (typein_lt_type _ a)).trans_le this refine (RelEmbedding.ofMonotone (fun a => ?_) fun a b => ?_).ordinal_type_le.trans_lt this @@ -828,6 +825,30 @@ theorem smul_eq_mul : ∀ (n : ℕ) (a : Ordinal), n • a = a * n | 0, a => by rw [zero_nsmul, Nat.cast_zero, mul_zero] | n + 1, a => by rw [succ_nsmul, Nat.cast_add, mul_add, Nat.cast_one, mul_one, smul_eq_mul n] +private theorem add_mul_limit_aux {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c) + (IH : ∀ c' < c, (a + b) * succ c' = a * succ c' + b) : (a + b) * c = a * c := + le_antisymm + ((mul_le_of_limit l).2 fun c' h => by + apply (mul_le_mul_left' (le_succ c') _).trans + rw [IH _ h] + apply (add_le_add_left _ _).trans + · rw [← mul_succ] + exact mul_le_mul_left' (succ_le_of_lt <| l.succ_lt h) _ + · rw [← ba] + exact le_add_right _ _) + (mul_le_mul_right' (le_add_right _ _) _) + +theorem add_mul_succ {a b : Ordinal} (c) (ba : b + a = a) : (a + b) * succ c = a * succ c + b := by + induction c using limitRecOn with + | H₁ => simp only [succ_zero, mul_one] + | H₂ c IH => + rw [mul_succ, IH, ← add_assoc, add_assoc _ b, ba, ← mul_succ] + | H₃ c l IH => + rw [mul_succ, add_mul_limit_aux ba l IH, mul_succ, add_assoc] + +theorem add_mul_limit {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c) : (a + b) * c = a * c := + add_mul_limit_aux ba l fun c' _ => add_mul_succ c' ba + /-! ### Division on ordinals -/ @@ -1464,8 +1485,8 @@ theorem sInf_compl_lt_ord_succ {ι : Type u} (f : ι → Ordinal.{u}) : -- TODO: remove `bsup` in favor of `iSup` in a future refactor. section bsup -set_option linter.deprecated false +set_option linter.deprecated false in private theorem sup_le_sup {ι ι' : Type u} (r : ι → ι → Prop) (r' : ι' → ι' → Prop) [IsWellOrder ι r] [IsWellOrder ι' r'] {o} (ho : type r = o) (ho' : type r' = o) (f : ∀ a < o, Ordinal.{max u v}) : @@ -1480,23 +1501,27 @@ private theorem sup_le_sup {ι ι' : Type u} (r : ι → ι → Prop) (r' : ι' simp_rw [familyOfBFamily', ← hj] apply le_sup +set_option linter.deprecated false in theorem sup_eq_sup {ι ι' : Type u} (r : ι → ι → Prop) (r' : ι' → ι' → Prop) [IsWellOrder ι r] [IsWellOrder ι' r'] {o : Ordinal.{u}} (ho : type r = o) (ho' : type r' = o) (f : ∀ a < o, Ordinal.{max u v}) : sup.{_, v} (familyOfBFamily' r ho f) = sup.{_, v} (familyOfBFamily' r' ho' f) := sup_eq_of_range_eq.{u, u, v} (by simp) +set_option linter.deprecated false in /-- The supremum of a family of ordinals indexed by the set of ordinals less than some `o : Ordinal.{u}`. This is a special case of `sup` over the family provided by `familyOfBFamily`. -/ def bsup (o : Ordinal.{u}) (f : ∀ a < o, Ordinal.{max u v}) : Ordinal.{max u v} := sup.{_, v} (familyOfBFamily o f) +set_option linter.deprecated false in @[simp] theorem sup_eq_bsup {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) : sup.{_, v} (familyOfBFamily o f) = bsup.{_, v} o f := rfl +set_option linter.deprecated false in @[simp] theorem sup_eq_bsup' {o : Ordinal.{u}} {ι} (r : ι → ι → Prop) [IsWellOrder ι r] (ho : type r = o) (f : ∀ a < o, Ordinal.{max u v}) : sup.{_, v} (familyOfBFamily' r ho f) = bsup.{_, v} o f := @@ -1507,6 +1532,7 @@ theorem sSup_eq_bsup {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) : congr rw [range_familyOfBFamily] +set_option linter.deprecated false in @[simp] theorem bsup_eq_sup' {ι : Type u} (r : ι → ι → Prop) [IsWellOrder ι r] (f : ι → Ordinal.{max u v}) : bsup.{_, v} _ (bfamilyOfFamily' r f) = sup.{_, v} f := by @@ -1518,6 +1544,7 @@ theorem bsup_eq_bsup {ι : Type u} (r r' : ι → ι → Prop) [IsWellOrder ι r bsup.{_, v} _ (bfamilyOfFamily' r f) = bsup.{_, v} _ (bfamilyOfFamily' r' f) := by rw [bsup_eq_sup', bsup_eq_sup'] +set_option linter.deprecated false in @[simp] theorem bsup_eq_sup {ι : Type u} (f : ι → Ordinal.{max u v}) : bsup.{_, v} _ (bfamilyOfFamily f) = sup.{_, v} f := @@ -1530,6 +1557,7 @@ theorem bsup_congr {o₁ o₂ : Ordinal.{u}} (f : ∀ a < o₁, Ordinal.{max u v -- Porting note: `rfl` is required. rfl +set_option linter.deprecated false in theorem bsup_le_iff {o f a} : bsup.{u, v} o f ≤ a ↔ ∀ i h, f i h ≤ a := sup_le_iff.trans ⟨fun h i hi => by @@ -1547,6 +1575,7 @@ theorem lt_bsup {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {a} : a < bsup.{_, v} o f ↔ ∃ i hi, a < f i hi := by simpa only [not_forall, not_le] using not_congr (@bsup_le_iff.{_, v} _ f a) +set_option linter.deprecated false in theorem IsNormal.bsup {f : Ordinal.{max u v} → Ordinal.{max u w}} (H : IsNormal f) {o : Ordinal.{u}} : ∀ (g : ∀ a < o, Ordinal), o ≠ 0 → f (bsup.{_, v} o g) = bsup.{_, w} o fun a h => f (g a h) := @@ -1558,6 +1587,7 @@ theorem lt_bsup_of_ne_bsup {o : Ordinal.{u}} {f : ∀ a < o, Ordinal.{max u v}} (∀ i h, f i h ≠ bsup.{_, v} o f) ↔ ∀ i h, f i h < bsup.{_, v} o f := ⟨fun hf _ _ => lt_of_le_of_ne (le_bsup _ _ _) (hf _ _), fun hf _ _ => ne_of_lt (hf _ _)⟩ +set_option linter.deprecated false in theorem bsup_not_succ_of_ne_bsup {o : Ordinal.{u}} {f : ∀ a < o, Ordinal.{max u v}} (hf : ∀ {i : Ordinal} (h : i < o), f i h ≠ bsup.{_, v} o f) (a) : a < bsup.{_, v} o f → succ a < bsup.{_, v} o f := by @@ -1589,6 +1619,7 @@ theorem bsup_const {o : Ordinal.{u}} (ho : o ≠ 0) (a : Ordinal.{max u v}) : (bsup.{_, v} o fun _ _ => a) = a := le_antisymm (bsup_le fun _ _ => le_rfl) (le_bsup _ 0 (Ordinal.pos_iff_ne_zero.2 ho)) +set_option linter.deprecated false in @[simp] theorem bsup_one (f : ∀ a < (1 : Ordinal), Ordinal) : bsup 1 f = f 0 zero_lt_one := by simp_rw [← sup_eq_bsup, sup_unique, familyOfBFamily, familyOfBFamily', typein_one_toType] @@ -1604,6 +1635,7 @@ theorem bsup_eq_of_brange_eq {o o'} {f : ∀ a < o, Ordinal} {g : ∀ a < o', Or (h : brange o f = brange o' g) : bsup.{u, max v w} o f = bsup.{v, max u w} o' g := (bsup_le_of_brange_subset.{u, v, w} h.le).antisymm (bsup_le_of_brange_subset.{v, u, w} h.ge) +set_option linter.deprecated false in theorem iSup_eq_bsup {o} {f : ∀ a < o, Ordinal} : ⨆ a : Iio o, f a.1 a.2 = bsup o f := by simp_rw [Iio, bsup, sup, iSup, range_familyOfBFamily, brange, range, Subtype.exists, mem_setOf] @@ -1612,17 +1644,19 @@ end bsup -- TODO: bring the lsub API in line with the sSup / iSup API, or deprecate it altogether. section lsub -set_option linter.deprecated false +set_option linter.deprecated false in /-- The least strict upper bound of a family of ordinals. -/ def lsub {ι} (f : ι → Ordinal) : Ordinal := sup (succ ∘ f) +set_option linter.deprecated false in @[simp] theorem sup_eq_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : sup.{_, v} (succ ∘ f) = lsub.{_, v} f := rfl +set_option linter.deprecated false in theorem lsub_le_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : lsub.{_, v} f ≤ a ↔ ∀ i, f i < a := by convert sup_le_iff.{_, v} (f := succ ∘ f) (a := a) using 2 @@ -1632,6 +1666,7 @@ theorem lsub_le_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : theorem lsub_le {ι} {f : ι → Ordinal} {a} : (∀ i, f i < a) → lsub f ≤ a := lsub_le_iff.2 +set_option linter.deprecated false in theorem lt_lsub {ι} (f : ι → Ordinal) (i) : f i < lsub f := succ_le_iff.1 (le_sup _ i) @@ -1639,19 +1674,23 @@ theorem lt_lsub_iff {ι : Type u} {f : ι → Ordinal.{max u v}} {a} : a < lsub.{_, v} f ↔ ∃ i, a ≤ f i := by simpa only [not_forall, not_lt, not_le] using not_congr (@lsub_le_iff.{_, v} _ f a) +set_option linter.deprecated false in theorem sup_le_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : sup.{_, v} f ≤ lsub.{_, v} f := sup_le fun i => (lt_lsub f i).le +set_option linter.deprecated false in theorem lsub_le_sup_succ {ι : Type u} (f : ι → Ordinal.{max u v}) : lsub.{_, v} f ≤ succ (sup.{_, v} f) := lsub_le fun i => lt_succ_iff.2 (le_sup f i) +set_option linter.deprecated false in theorem sup_eq_lsub_or_sup_succ_eq_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : sup.{_, v} f = lsub.{_, v} f ∨ succ (sup.{_, v} f) = lsub.{_, v} f := by cases' eq_or_lt_of_le (sup_le_lsub.{_, v} f) with h h · exact Or.inl h · exact Or.inr ((succ_le_of_lt h).antisymm (lsub_le_sup_succ f)) +set_option linter.deprecated false in theorem sup_succ_le_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : succ (sup.{_, v} f) ≤ lsub.{_, v} f ↔ ∃ i, f i = sup.{_, v} f := by refine ⟨fun h => ?_, ?_⟩ @@ -1661,10 +1700,12 @@ theorem sup_succ_le_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : rw [succ_le_iff, ← hf] exact lt_lsub _ _ +set_option linter.deprecated false in theorem sup_succ_eq_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : succ (sup.{_, v} f) = lsub.{_, v} f ↔ ∃ i, f i = sup.{_, v} f := (lsub_le_sup_succ f).le_iff_eq.symm.trans (sup_succ_le_lsub f) +set_option linter.deprecated false in theorem sup_eq_lsub_iff_succ {ι : Type u} (f : ι → Ordinal.{max u v}) : sup.{_, v} f = lsub.{_, v} f ↔ ∀ a < lsub.{_, v} f, succ a < lsub.{_, v} f := by refine ⟨fun h => ?_, fun hf => le_antisymm (sup_le_lsub f) (lsub_le fun i => ?_)⟩ @@ -1680,6 +1721,7 @@ theorem sup_eq_lsub_iff_succ {ι : Type u} (f : ι → Ordinal.{max u v}) : rw [heq] at this exact this.false +set_option linter.deprecated false in theorem sup_eq_lsub_iff_lt_sup {ι : Type u} (f : ι → Ordinal.{max u v}) : sup.{_, v} f = lsub.{_, v} f ↔ ∀ i, f i < sup.{_, v} f := ⟨fun h i => by @@ -1702,14 +1744,17 @@ theorem lsub_eq_zero_iff {ι : Type u} (f : ι → Ordinal.{max u v}) : rw [h] at this exact this.false +set_option linter.deprecated false in @[simp] theorem lsub_const {ι} [Nonempty ι] (o : Ordinal) : (lsub fun _ : ι => o) = succ o := sup_const (succ o) +set_option linter.deprecated false in @[simp] theorem lsub_unique {ι} [Unique ι] (f : ι → Ordinal) : lsub f = succ (f default) := sup_unique _ +set_option linter.deprecated false in theorem lsub_le_of_range_subset {ι ι'} {f : ι → Ordinal} {g : ι' → Ordinal} (h : Set.range f ⊆ Set.range g) : lsub.{u, max v w} f ≤ lsub.{v, max u w} g := sup_le_of_range_subset.{u, v, w} (by convert Set.image_subset succ h <;> apply Set.range_comp) @@ -1718,6 +1763,7 @@ theorem lsub_eq_of_range_eq {ι ι'} {f : ι → Ordinal} {g : ι' → Ordinal} (h : Set.range f = Set.range g) : lsub.{u, max v w} f = lsub.{v, max u w} g := (lsub_le_of_range_subset.{u, v, w} h.le).antisymm (lsub_le_of_range_subset.{v, u, w} h.ge) +set_option linter.deprecated false in @[simp] theorem lsub_sum {α : Type u} {β : Type v} (f : α ⊕ β → Ordinal) : lsub.{max u v, w} f = @@ -1731,6 +1777,7 @@ theorem lsub_not_mem_range {ι : Type u} (f : ι → Ordinal.{max u v}) : theorem nonempty_compl_range {ι : Type u} (f : ι → Ordinal.{max u v}) : (Set.range f)ᶜ.Nonempty := ⟨_, lsub_not_mem_range.{_, v} f⟩ +set_option linter.deprecated false in @[simp] theorem lsub_typein (o : Ordinal) : lsub.{u, u} (typein (α := o.toType) (· < ·)) = o := (lsub_le.{u, u} typein_lt_self).antisymm @@ -1740,11 +1787,13 @@ theorem lsub_typein (o : Ordinal) : lsub.{u, u} (typein (α := o.toType) (· < conv_rhs at h => rw [← type_lt o] simpa [typein_enum] using lt_lsub.{u, u} (typein (· < ·)) (enum (· < ·) ⟨_, h⟩)) +set_option linter.deprecated false in theorem sup_typein_limit {o : Ordinal} (ho : ∀ a, a < o → succ a < o) : sup.{u, u} (typein ((· < ·) : o.toType → o.toType → Prop)) = o := by -- Porting note: `rwa` → `rw` & `assumption` rw [(sup_eq_lsub_iff_succ.{u, u} (typein (· < ·))).2] <;> rw [lsub_typein o]; assumption +set_option linter.deprecated false in @[simp] theorem sup_typein_succ {o : Ordinal} : sup.{u, u} (typein ((· < ·) : (succ o).toType → (succ o).toType → Prop)) = o := by @@ -1764,7 +1813,6 @@ end lsub -- both of them at once. section blsub -set_option linter.deprecated false /-- The least strict upper bound of a family of ordinals indexed by the set of ordinals less than some `o : Ordinal.{u}`. @@ -1870,7 +1918,7 @@ theorem bsup_eq_blsub_iff_lt_bsup {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max apply lt_blsub, fun h => le_antisymm (bsup_le_blsub f) (blsub_le h)⟩ theorem bsup_eq_blsub_of_lt_succ_limit {o : Ordinal.{u}} (ho : IsLimit o) - {f : ∀ a < o, Ordinal.{max u v}} (hf : ∀ a ha, f a ha < f (succ a) (ho.2 a ha)) : + {f : ∀ a < o, Ordinal.{max u v}} (hf : ∀ a ha, f a ha < f (succ a) (ho.succ_lt ha)) : bsup.{_, v} o f = blsub.{_, v} o f := by rw [bsup_eq_blsub_iff_lt_bsup] exact fun i hi => (hf i hi).trans_le (le_bsup f _ _) @@ -1948,7 +1996,7 @@ theorem blsub_comp {o o' : Ordinal.{max u v}} {f : ∀ a < o, Ordinal.{max u v w theorem IsNormal.bsup_eq {f : Ordinal.{u} → Ordinal.{max u v}} (H : IsNormal f) {o : Ordinal.{u}} (h : IsLimit o) : (Ordinal.bsup.{_, v} o fun x _ => f x) = f o := by - rw [← IsNormal.bsup.{u, u, v} H (fun x _ => x) h.1, bsup_id_limit h.2] + rw [← IsNormal.bsup.{u, u, v} H (fun x _ => x) h.ne_bot, bsup_id_limit fun _ ↦ h.succ_lt] theorem IsNormal.blsub_eq {f : Ordinal.{u} → Ordinal.{max u v}} (H : IsNormal f) {o : Ordinal.{u}} (h : IsLimit o) : (blsub.{_, v} o fun x _ => f x) = f o := by @@ -1992,6 +2040,7 @@ def blsub₂ (o₁ o₂ : Ordinal) (op : {a : Ordinal} → (a < o₁) → {b : O Ordinal := lsub (fun x : o₁.toType × o₂.toType => op (typein_lt_self x.1) (typein_lt_self x.2)) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-11")] theorem lt_blsub₂ {o₁ o₂ : Ordinal} (op : {a : Ordinal} → (a < o₁) → {b : Ordinal} → (b < o₂) → Ordinal) {a b : Ordinal} @@ -2003,7 +2052,6 @@ theorem lt_blsub₂ {o₁ o₂ : Ordinal} end blsub section mex -set_option linter.deprecated false /-! ### Minimum excluded ordinals -/ @@ -2013,33 +2061,40 @@ set_option linter.deprecated false def mex {ι : Type u} (f : ι → Ordinal.{max u v}) : Ordinal := sInf (Set.range f)ᶜ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_not_mem_range {ι : Type u} (f : ι → Ordinal.{max u v}) : mex.{_, v} f ∉ Set.range f := csInf_mem (nonempty_compl_range.{_, v} f) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem le_mex_of_forall {ι : Type u} {f : ι → Ordinal.{max u v}} {a : Ordinal} (H : ∀ b < a, ∃ i, f i = b) : a ≤ mex.{_, v} f := by by_contra! h exact mex_not_mem_range f (H _ h) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem ne_mex {ι : Type u} (f : ι → Ordinal.{max u v}) : ∀ i, f i ≠ mex.{_, v} f := by simpa using mex_not_mem_range.{_, v} f +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_le_of_ne {ι} {f : ι → Ordinal} {a} (ha : ∀ i, f i ≠ a) : mex f ≤ a := csInf_le' (by simp [ha]) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem exists_of_lt_mex {ι} {f : ι → Ordinal} {a} (ha : a < mex f) : ∃ i, f i = a := by by_contra! ha' exact ha.not_le (mex_le_of_ne ha') +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_le_lsub {ι : Type u} (f : ι → Ordinal.{max u v}) : mex.{_, v} f ≤ lsub.{_, v} f := csInf_le' (lsub_not_mem_range f) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem mex_monotone {α β : Type u} {f : α → Ordinal.{max u v}} {g : β → Ordinal.{max u v}} (h : Set.range f ⊆ Set.range g) : mex.{_, v} f ≤ mex.{_, v} g := by @@ -2048,6 +2103,7 @@ theorem mex_monotone {α β : Type u} {f : α → Ordinal.{max u v}} {g : β → rw [← hj] at hi exact ne_mex g j hi +set_option linter.deprecated false in @[deprecated sInf_compl_lt_ord_succ (since := "2024-09-20")] theorem mex_lt_ord_succ_mk {ι : Type u} (f : ι → Ordinal.{u}) : mex.{_, u} f < (succ #ι).ord := by @@ -2064,6 +2120,7 @@ theorem mex_lt_ord_succ_mk {ι : Type u} (f : ι → Ordinal.{u}) : convert Cardinal.mk_le_of_injective hg rw [Cardinal.mk_ord_toType (succ #ι)] +set_option linter.deprecated false in /-- The minimum excluded ordinal of a family of ordinals indexed by the set of ordinals less than some `o : Ordinal.{u}`. This is a special case of `mex` over the family provided by `familyOfBFamily`. @@ -2073,17 +2130,20 @@ theorem mex_lt_ord_succ_mk {ι : Type u} (f : ι → Ordinal.{u}) : def bmex (o : Ordinal) (f : ∀ a < o, Ordinal) : Ordinal := mex (familyOfBFamily o f) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_not_mem_brange {o : Ordinal} (f : ∀ a < o, Ordinal) : bmex o f ∉ brange o f := by rw [← range_familyOfBFamily] apply mex_not_mem_range +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem le_bmex_of_forall {o : Ordinal} (f : ∀ a < o, Ordinal) {a : Ordinal} (H : ∀ b < a, ∃ i hi, f i hi = b) : a ≤ bmex o f := by by_contra! h exact bmex_not_mem_brange f (H _ h) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem ne_bmex {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {i} (hi) : f i hi ≠ bmex.{_, v} o f := by @@ -2092,28 +2152,33 @@ theorem ne_bmex {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) {i} (hi) : -- Porting note: `familyOfBFamily_enum` → `typein_enum` rw [typein_enum] +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_le_of_ne {o : Ordinal} {f : ∀ a < o, Ordinal} {a} (ha : ∀ i hi, f i hi ≠ a) : bmex o f ≤ a := mex_le_of_ne fun _i => ha _ _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem exists_of_lt_bmex {o : Ordinal} {f : ∀ a < o, Ordinal} {a} (ha : a < bmex o f) : ∃ i hi, f i hi = a := by cases' exists_of_lt_mex ha with i hi exact ⟨_, typein_lt_self i, hi⟩ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_le_blsub {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{max u v}) : bmex.{_, v} o f ≤ blsub.{_, v} o f := mex_le_lsub _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-20")] theorem bmex_monotone {o o' : Ordinal.{u}} {f : ∀ a < o, Ordinal.{max u v}} {g : ∀ a < o', Ordinal.{max u v}} (h : brange o f ⊆ brange o' g) : bmex.{_, v} o f ≤ bmex.{_, v} o' g := mex_monotone (by rwa [range_familyOfBFamily, range_familyOfBFamily]) +set_option linter.deprecated false in @[deprecated sInf_compl_lt_ord_succ (since := "2024-09-20")] theorem bmex_lt_ord_succ_card {o : Ordinal.{u}} (f : ∀ a < o, Ordinal.{u}) : bmex.{_, u} o f < (succ o.card).ord := by @@ -2267,24 +2332,8 @@ theorem lift_ofNat (n : ℕ) [n.AtLeastTwo] : lift.{u, v} (no_index (OfNat.ofNat n)) = OfNat.ofNat n := lift_natCast n -end Ordinal - /-! ### Properties of ω -/ - -namespace Cardinal - -open Ordinal - -@[simp] -theorem add_one_of_aleph0_le {c} (h : ℵ₀ ≤ c) : c + 1 = c := by - rw [add_comm, ← card_ord c, ← card_one, ← card_add, one_add_of_omega0_le] - rwa [← ord_aleph0, ord_le_ord] - -end Cardinal - -namespace Ordinal - theorem lt_add_of_limit {a b c : Ordinal.{u}} (h : IsLimit c) : a < b + c ↔ ∃ c' < c, a < b + c' := by -- Porting note: `bex_def` is required. @@ -2316,10 +2365,11 @@ theorem one_lt_omega0 : 1 < ω := by simpa only [Nat.cast_one] using nat_lt_omeg @[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias one_lt_omega := one_lt_omega0 -theorem isLimit_omega0 : IsLimit ω := - ⟨omega0_ne_zero, fun o h => by - let ⟨n, e⟩ := lt_omega0.1 h - rw [e]; exact nat_lt_omega0 (n + 1)⟩ +theorem isLimit_omega0 : IsLimit ω := by + rw [isLimit_iff, isSuccPrelimit_iff_succ_lt] + refine ⟨omega0_ne_zero, fun o h => ?_⟩ + obtain ⟨n, rfl⟩ := lt_omega0.1 h + exact nat_lt_omega0 (n + 1) @[deprecated "No deprecation message was provided." (since := "2024-10-14")] alias omega0_isLimit := isLimit_omega0 @@ -2349,8 +2399,8 @@ theorem sup_natCast : sup Nat.cast = ω := alias sup_nat_cast := sup_natCast theorem nat_lt_limit {o} (h : IsLimit o) : ∀ n : ℕ, ↑n < o - | 0 => lt_of_le_of_ne (Ordinal.zero_le o) h.1.symm - | n + 1 => h.2 _ (nat_lt_limit h n) + | 0 => h.pos + | n + 1 => h.succ_lt (nat_lt_limit h n) theorem omega0_le_of_isLimit {o} (h : IsLimit o) : ω ≤ o := omega0_le.2 fun n => le_of_lt <| nat_lt_limit h n @@ -2358,8 +2408,39 @@ theorem omega0_le_of_isLimit {o} (h : IsLimit o) : ω ≤ o := @[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias omega_le_of_isLimit := omega0_le_of_isLimit +theorem natCast_add_omega0 (n : ℕ) : n + ω = ω := by + refine le_antisymm (le_of_forall_lt fun a ha ↦ ?_) (le_add_left _ _) + obtain ⟨b, hb', hb⟩ := (lt_add_iff omega0_ne_zero).1 ha + obtain ⟨m, rfl⟩ := lt_omega0.1 hb' + apply hb.trans_lt + exact_mod_cast nat_lt_omega0 (n + m) + +theorem one_add_omega0 : 1 + ω = ω := + mod_cast natCast_add_omega0 1 + +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] +alias one_add_omega := one_add_omega0 + +theorem add_omega0 {a : Ordinal} (h : a < ω) : a + ω = ω := by + obtain ⟨n, rfl⟩ := lt_omega0.1 h + exact natCast_add_omega0 n + +@[deprecated (since := "2024-09-30")] +alias add_omega := add_omega0 + +@[simp] +theorem natCast_add_of_omega0_le {o} (h : ω ≤ o) (n : ℕ) : n + o = o := by + rw [← Ordinal.add_sub_cancel_of_le h, ← add_assoc, natCast_add_omega0] + +@[simp] +theorem one_add_of_omega0_le {o} (h : ω ≤ o) : 1 + o = o := + mod_cast natCast_add_of_omega0_le h 1 + +@[deprecated "No deprecation message was provided." (since := "2024-09-30")] +alias one_add_of_omega_le := one_add_of_omega0_le + theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ a := by - refine ⟨fun l => ⟨l.1, ⟨a / ω, le_antisymm ?_ (mul_div_le _ _)⟩⟩, fun h => ?_⟩ + refine ⟨fun l => ⟨l.ne_zero, ⟨a / ω, le_antisymm ?_ (mul_div_le _ _)⟩⟩, fun h => ?_⟩ · refine (limit_le l).2 fun x hx => le_of_lt ?_ rw [← div_lt omega0_ne_zero, ← succ_le_iff, le_div omega0_ne_zero, mul_succ, add_le_of_limit isLimit_omega0] @@ -2376,44 +2457,6 @@ theorem isLimit_iff_omega0_dvd {a : Ordinal} : IsLimit a ↔ a ≠ 0 ∧ ω ∣ @[deprecated "No deprecation message was provided." (since := "2024-09-30")] alias isLimit_iff_omega_dvd := isLimit_iff_omega0_dvd -theorem add_mul_limit_aux {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c) - (IH : ∀ c' < c, (a + b) * succ c' = a * succ c' + b) : (a + b) * c = a * c := - le_antisymm - ((mul_le_of_limit l).2 fun c' h => by - apply (mul_le_mul_left' (le_succ c') _).trans - rw [IH _ h] - apply (add_le_add_left _ _).trans - · rw [← mul_succ] - exact mul_le_mul_left' (succ_le_of_lt <| l.2 _ h) _ - · rw [← ba] - exact le_add_right _ _) - (mul_le_mul_right' (le_add_right _ _) _) - -theorem add_mul_succ {a b : Ordinal} (c) (ba : b + a = a) : (a + b) * succ c = a * succ c + b := by - induction c using limitRecOn with - | H₁ => simp only [succ_zero, mul_one] - | H₂ c IH => - rw [mul_succ, IH, ← add_assoc, add_assoc _ b, ba, ← mul_succ] - | H₃ c l IH => - -- Porting note: Unused. - -- have := add_mul_limit_aux ba l IH - rw [mul_succ, add_mul_limit_aux ba l IH, mul_succ, add_assoc] - -theorem add_mul_limit {a b c : Ordinal} (ba : b + a = a) (l : IsLimit c) : (a + b) * c = a * c := - add_mul_limit_aux ba l fun c' _ => add_mul_succ c' ba - -theorem add_le_of_forall_add_lt {a b c : Ordinal} (hb : 0 < b) (h : ∀ d < b, a + d < c) : - a + b ≤ c := by - have H : a + (c - a) = c := - Ordinal.add_sub_cancel_of_le - (by - rw [← add_zero a] - exact (h _ hb).le) - rw [← H] - apply add_le_add_left _ a - by_contra! hb - exact (h _ hb).ne H - theorem IsNormal.apply_omega0 {f : Ordinal.{u} → Ordinal.{v}} (hf : IsNormal f) : ⨆ n : ℕ, f n = f ω := by rw [← iSup_natCast, hf.map_iSup] @@ -2450,7 +2493,13 @@ namespace Cardinal open Ordinal +@[simp] +theorem add_one_of_aleph0_le {c} (h : ℵ₀ ≤ c) : c + 1 = c := by + rw [add_comm, ← card_ord c, ← card_one, ← card_add, one_add_of_omega0_le] + rwa [← ord_aleph0, ord_le_ord] + theorem isLimit_ord {c} (co : ℵ₀ ≤ c) : (ord c).IsLimit := by + rw [isLimit_iff, isSuccPrelimit_iff_succ_lt] refine ⟨fun h => aleph0_ne_zero ?_, fun a => lt_imp_lt_of_le_imp_le fun h => ?_⟩ · rw [← Ordinal.le_zero, ord_le] at h simpa only [card_zero, nonpos_iff_eq_zero] using co.trans h @@ -2465,7 +2514,7 @@ theorem isLimit_ord {c} (co : ℵ₀ ≤ c) : (ord c).IsLimit := by alias ord_isLimit := isLimit_ord theorem noMaxOrder {c} (h : ℵ₀ ≤ c) : NoMaxOrder c.ord.toType := - toType_noMax_of_succ_lt (isLimit_ord h).2 + toType_noMax_of_succ_lt fun _ ↦ (isLimit_ord h).succ_lt end Cardinal diff --git a/Mathlib/SetTheory/Ordinal/Basic.lean b/Mathlib/SetTheory/Ordinal/Basic.lean index ec9a34419fbf4..1693d12052eee 100644 --- a/Mathlib/SetTheory/Ordinal/Basic.lean +++ b/Mathlib/SetTheory/Ordinal/Basic.lean @@ -87,10 +87,8 @@ namespace WellOrder instance inhabited : Inhabited WellOrder := ⟨⟨PEmpty, _, inferInstanceAs (IsWellOrder PEmpty EmptyRelation)⟩⟩ -@[simp] -theorem eta (o : WellOrder) : mk o.α o.r o.wo = o := by - cases o - rfl +@[deprecated "No deprecation message was provided." (since := "2024-10-24")] +theorem eta (o : WellOrder) : mk o.α o.r o.wo = o := rfl end WellOrder @@ -130,6 +128,9 @@ namespace Ordinal def type (r : α → α → Prop) [wo : IsWellOrder α r] : Ordinal := ⟦⟨α, r, wo⟩⟧ +/-- `typeLT α` is an abbreviation for the order type of the `<` relation of `α`. -/ +scoped notation "typeLT " α:70 => @Ordinal.type α (· < ·) inferInstance + instance zero : Zero Ordinal := ⟨type <| @EmptyRelation PEmpty⟩ @@ -139,22 +140,22 @@ instance inhabited : Inhabited Ordinal := instance one : One Ordinal := ⟨type <| @EmptyRelation PUnit⟩ -@[simp] -theorem type_def' (w : WellOrder) : ⟦w⟧ = type w.r := by - cases w - rfl +@[deprecated "Avoid using `Quotient.mk` to construct an `Ordinal` directly." + (since := "2024-10-24")] +theorem type_def' (w : WellOrder) : ⟦w⟧ = type w.r := rfl -@[simp] -theorem type_def (r) [wo : IsWellOrder α r] : (⟦⟨α, r, wo⟩⟧ : Ordinal) = type r := by - rfl + +@[deprecated "Avoid using `Quotient.mk` to construct an `Ordinal` directly." + (since := "2024-10-24")] +theorem type_def (r) [wo : IsWellOrder α r] : (⟦⟨α, r, wo⟩⟧ : Ordinal) = type r := rfl @[simp] -theorem type_toType (o : Ordinal) : type (α := o.toType) (· < ·) = o := - (type_def' _).symm.trans <| Quotient.out_eq o +theorem type_toType (o : Ordinal) : typeLT o.toType = o := + o.out_eq @[deprecated type_toType (since := "2024-10-22")] -theorem type_lt (o : Ordinal) : type (α := o.toType) (· < ·) = o := - (type_def' _).symm.trans <| Quotient.out_eq o +theorem type_lt (o : Ordinal) : typeLT o.toType = o := + o.out_eq @[deprecated type_toType (since := "2024-08-26")] theorem type_out (o : Ordinal) : Ordinal.type o.out.r = o := @@ -761,14 +762,14 @@ theorem lt_lift_iff {a : Ordinal.{u}} {b : Ordinal.{max u v}} : /-- `ω` is the first infinite ordinal, defined as the order type of `ℕ`. -/ def omega0 : Ordinal.{u} := - lift <| @type ℕ (· < ·) _ + lift (typeLT ℕ) @[inherit_doc] scoped notation "ω" => Ordinal.omega0 /-- Note that the presence of this lemma makes `simp [omega0]` form a loop. -/ @[simp] -theorem type_nat_lt : @type ℕ (· < ·) _ = ω := +theorem type_nat_lt : typeLT ℕ = ω := (lift_id _).symm @[simp] @@ -975,9 +976,9 @@ theorem le_enum_succ {o : Ordinal} (a : (succ o).toType) : of `Ordinal.{v}` (when `u < v`). It is an inaccessible cardinal. -/ @[pp_with_univ, nolint checkUnivs] def univ : Ordinal.{max (u + 1) v} := - lift.{v, u + 1} (@type Ordinal (· < ·) _) + lift.{v, u + 1} (typeLT Ordinal) -theorem univ_id : univ.{u, u + 1} = @type Ordinal (· < ·) _ := +theorem univ_id : univ.{u, u + 1} = typeLT Ordinal := lift_id _ @[simp] @@ -1041,12 +1042,12 @@ set_option linter.deprecated false in theorem lift.principalSeg_top : (lift.principalSeg.{u, v}).top = univ.{u, v} := rfl -theorem liftPrincipalSeg_top' : liftPrincipalSeg.{u, u + 1}.top = @type Ordinal (· < ·) _ := by +theorem liftPrincipalSeg_top' : liftPrincipalSeg.{u, u + 1}.top = typeLT Ordinal := by simp only [liftPrincipalSeg_top, univ_id] set_option linter.deprecated false in @[deprecated liftPrincipalSeg_top (since := "2024-09-21")] -theorem lift.principalSeg_top' : lift.principalSeg.{u, u + 1}.top = @type Ordinal (· < ·) _ := by +theorem lift.principalSeg_top' : lift.principalSeg.{u, u + 1}.top = typeLT Ordinal := by simp only [lift.principalSeg_top, univ_id] end Ordinal @@ -1428,7 +1429,7 @@ theorem card_eq_ofNat {o} {n : ℕ} [n.AtLeastTwo] : theorem type_fintype (r : α → α → Prop) [IsWellOrder α r] [Fintype α] : type r = Fintype.card α := by rw [← card_eq_nat, card_type, mk_fintype] -theorem type_fin (n : ℕ) : @type (Fin n) (· < ·) _ = n := by simp +theorem type_fin (n : ℕ) : typeLT (Fin n) = n := by simp end Ordinal diff --git a/Mathlib/SetTheory/Ordinal/FixedPoint.lean b/Mathlib/SetTheory/Ordinal/FixedPoint.lean index 84f2f8db36b0d..00a1b45e0c167 100644 --- a/Mathlib/SetTheory/Ordinal/FixedPoint.lean +++ b/Mathlib/SetTheory/Ordinal/FixedPoint.lean @@ -226,8 +226,6 @@ end section -set_option linter.deprecated false - variable {o : Ordinal.{u}} {f : ∀ b < o, Ordinal.{max u v} → Ordinal.{max u v}} /-- The next common fixed point, at least `a`, for a family of normal functions indexed by ordinals. @@ -238,47 +236,56 @@ def nfpBFamily (o : Ordinal.{u}) (f : ∀ b < o, Ordinal.{max u v} → Ordinal.{ Ordinal.{max u v} → Ordinal.{max u v} := nfpFamily (familyOfBFamily o f) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_eq_nfpFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : nfpBFamily.{u, v} o f = nfpFamily (familyOfBFamily o f) := rfl +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem foldr_le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a l) : List.foldr (familyOfBFamily o f) a l ≤ nfpBFamily.{u, v} o f a := Ordinal.le_iSup _ _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem le_nfpBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) (a) : a ≤ nfpBFamily.{u, v} o f a := Ordinal.le_iSup (fun _ ↦ List.foldr _ a _) [] +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem lt_nfpBFamily {a b} : a < nfpBFamily.{u, v} o f b ↔ ∃ l, a < List.foldr (familyOfBFamily o f) b l := Ordinal.lt_iSup_iff +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_iff {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a b} : nfpBFamily.{u, v} o f a ≤ b ↔ ∀ l, List.foldr (familyOfBFamily o f) a l ≤ b := Ordinal.iSup_le_iff +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le {o : Ordinal} {f : ∀ b < o, Ordinal → Ordinal} {a b} : (∀ l, List.foldr (familyOfBFamily o f) a l ≤ b) → nfpBFamily.{u, v} o f a ≤ b := Ordinal.iSup_le +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_monotone (hf : ∀ i hi, Monotone (f i hi)) : Monotone (nfpBFamily.{u, v} o f) := nfpFamily_monotone fun _ => hf _ _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_lt_nfpBFamily (H : ∀ i hi, IsNormal (f i hi)) {a b} (hb : b < nfpBFamily.{u, v} o f a) (i hi) : f i hi b < nfpBFamily.{u, v} o f a := by rw [← familyOfBFamily_enum o f] apply apply_lt_nfpFamily (fun _ => H _ _) hb +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_lt_nfpBFamily_iff (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∀ i hi, f i hi b < nfpBFamily.{u, v} o f a) ↔ b < nfpBFamily.{u, v} o f a := @@ -287,6 +294,7 @@ theorem apply_lt_nfpBFamily_iff (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) refine (apply_lt_nfpFamily_iff ?_).1 fun _ => h _ _ exact fun _ => H _ _, apply_lt_nfpBFamily H⟩ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_apply (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∃ i hi, nfpBFamily.{u, v} o f a ≤ f i hi b) ↔ nfpBFamily.{u, v} o f a ≤ b := by @@ -294,11 +302,13 @@ theorem nfpBFamily_le_apply (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a push_neg exact apply_lt_nfpBFamily_iff.{u, v} ho H +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_le_fp (H : ∀ i hi, Monotone (f i hi)) {a b} (ab : a ≤ b) (h : ∀ i hi, f i hi b ≤ b) : nfpBFamily.{u, v} o f a ≤ b := nfpFamily_le_fp (fun _ => H _ _) ab fun _ => h _ _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_fp {i hi} (H : IsNormal (f i hi)) (a) : f i hi (nfpBFamily.{u, v} o f a) = nfpBFamily.{u, v} o f a := by @@ -307,6 +317,7 @@ theorem nfpBFamily_fp {i hi} (H : IsNormal (f i hi)) (a) : rw [familyOfBFamily_enum] exact H +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem apply_le_nfpBFamily (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a b} : (∀ i hi, f i hi b ≤ nfpBFamily.{u, v} o f a) ↔ b ≤ nfpBFamily.{u, v} o f a := by @@ -316,10 +327,12 @@ theorem apply_le_nfpBFamily (ho : o ≠ 0) (H : ∀ i hi, IsNormal (f i hi)) {a · rw [← nfpBFamily_fp (H i hi)] exact (H i hi).monotone h +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem nfpBFamily_eq_self {a} (h : ∀ i hi, f i hi a = a) : nfpBFamily.{u, v} o f a = a := nfpFamily_eq_self fun _ => h _ _ +set_option linter.deprecated false in /-- A generalization of the fixed point lemma for normal functions: any family of normal functions has an unbounded set of common fixed points. -/ @[deprecated "No deprecation message was provided." (since := "2024-10-14")] @@ -330,6 +343,7 @@ theorem not_bddAbove_fp_bfamily (H : ∀ i hi, IsNormal (f i hi)) : rw [Set.mem_iInter₂] exact fun i hi ↦ nfpBFamily_fp (H i hi) _ +set_option linter.deprecated false in /-- A generalization of the fixed point lemma for normal functions: any family of normal functions has an unbounded set of common fixed points. -/ @[deprecated not_bddAbove_fp_bfamily (since := "2024-09-20")] @@ -347,11 +361,13 @@ def derivBFamily (o : Ordinal.{u}) (f : ∀ b < o, Ordinal.{max u v} → Ordinal Ordinal.{max u v} → Ordinal.{max u v} := derivFamily (familyOfBFamily o f) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem derivBFamily_eq_derivFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : derivBFamily.{u, v} o f = derivFamily (familyOfBFamily o f) := rfl +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem isNormal_derivBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) : IsNormal (derivBFamily o f) := @@ -360,6 +376,7 @@ theorem isNormal_derivBFamily {o : Ordinal} (f : ∀ b < o, Ordinal → Ordinal) @[deprecated isNormal_derivBFamily (since := "2024-10-11")] alias derivBFamily_isNormal := isNormal_derivBFamily +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem derivBFamily_fp {i hi} (H : IsNormal (f i hi)) (a : Ordinal) : f i hi (derivBFamily.{u, v} o f a) = derivBFamily.{u, v} o f a := by @@ -368,6 +385,7 @@ theorem derivBFamily_fp {i hi} (H : IsNormal (f i hi)) (a : Ordinal) : rw [familyOfBFamily_enum] exact H +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem le_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : (∀ i hi, f i hi a ≤ a) ↔ ∃ b, derivBFamily.{u, v} o f b = a := by @@ -378,6 +396,7 @@ theorem le_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : apply h · exact fun _ => H _ _ +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem fp_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : (∀ i hi, f i hi a = a) ↔ ∃ b, derivBFamily.{u, v} o f b = a := by @@ -386,6 +405,7 @@ theorem fp_iff_derivBFamily (H : ∀ i hi, IsNormal (f i hi)) {a} : rw [← (H i hi).le_iff_eq] exact h i hi +set_option linter.deprecated false in /-- For a family of normal functions, `Ordinal.derivBFamily` enumerates the common fixed points. -/ @[deprecated "No deprecation message was provided." (since := "2024-10-14")] theorem derivBFamily_eq_enumOrd (H : ∀ i hi, IsNormal (f i hi)) : diff --git a/Mathlib/SetTheory/Ordinal/Notation.lean b/Mathlib/SetTheory/Ordinal/Notation.lean index 02806888024eb..9d8409124777a 100644 --- a/Mathlib/SetTheory/Ordinal/Notation.lean +++ b/Mathlib/SetTheory/Ordinal/Notation.lean @@ -802,8 +802,8 @@ theorem repr_opow_aux₁ {e a} [Ne : NF e] [Na : NF a] {a' : Ordinal} (e0 : repr · apply (mul_le_mul_left' (le_succ b) _).trans rw [← add_one_eq_succ, add_mul_succ _ (one_add_of_omega0_le h), add_one_eq_succ, succ_le_iff, Ordinal.mul_lt_mul_iff_left (Ordinal.pos_iff_ne_zero.2 e0)] - exact isLimit_omega0.2 _ l - · apply (principal_mul_omega0 (isLimit_omega0.2 _ h) l).le.trans + exact isLimit_omega0.succ_lt l + · apply (principal_mul_omega0 (isLimit_omega0.succ_lt h) l).le.trans simpa using mul_le_mul_right' (one_le_iff_ne_zero.2 e0) ω section @@ -831,7 +831,7 @@ theorem repr_opow_aux₂ {a0 a'} [N0 : NF a0] [Na' : NF a'] (m : ℕ) (d : ω by_cases h : m = 0 · simp only [R, R', h, ONote.ofNat, Nat.cast_zero, zero_add, ONote.repr, mul_zero, ONote.opowAux, add_zero] - · simp only [R', ONote.repr_scale, ONote.repr, ONote.mulNat_eq_mul, ONote.opowAux, + · simp only [α', ω0, R, R', ONote.repr_scale, ONote.repr, ONote.mulNat_eq_mul, ONote.opowAux, ONote.repr_ofNat, ONote.repr_mul, ONote.repr_add, Ordinal.opow_mul, ONote.zero_add] have α0 : 0 < α' := by simpa [lt_def, repr] using oadd_pos a0 n a' have ω00 : 0 < ω0 ^ (k : Ordinal) := opow_pos _ (opow_pos _ omega0_pos) diff --git a/Mathlib/SetTheory/Ordinal/Principal.lean b/Mathlib/SetTheory/Ordinal/Principal.lean index 194abeabc7c50..d993ba3d10462 100644 --- a/Mathlib/SetTheory/Ordinal/Principal.lean +++ b/Mathlib/SetTheory/Ordinal/Principal.lean @@ -162,8 +162,9 @@ theorem principal_add_of_le_one (ho : o ≤ 1) : Principal (· + ·) o := by · exact principal_zero · exact principal_add_one -theorem isLimit_of_principal_add (ho₁ : 1 < o) (ho : Principal (· + ·) o) : o.IsLimit := - ⟨ho₁.ne_bot, fun _ ha ↦ ho ha ho₁⟩ +theorem isLimit_of_principal_add (ho₁ : 1 < o) (ho : Principal (· + ·) o) : o.IsLimit := by + rw [isLimit_iff, isSuccPrelimit_iff_succ_lt] + exact ⟨ho₁.ne_bot, fun _ ha ↦ ho ha ho₁⟩ @[deprecated (since := "2024-10-16")] alias principal_add_isLimit := isLimit_of_principal_add @@ -194,19 +195,6 @@ theorem principal_add_iff_add_lt_ne_self : Principal (· + ·) a ↔ ∀ b < a, rcases exists_lt_add_of_not_principal_add ha with ⟨b, hb, c, hc, rfl⟩ exact (H b hb c hc).irrefl⟩ -theorem add_omega0 (h : a < ω) : a + ω = ω := by - rcases lt_omega0.1 h with ⟨n, rfl⟩ - clear h; induction' n with n IH - · rw [Nat.cast_zero, zero_add] - · rwa [Nat.cast_succ, add_assoc, one_add_of_omega0_le (le_refl _)] - -@[deprecated (since := "2024-09-30")] -alias add_omega := add_omega0 - -@[simp] -theorem natCast_add_omega0 (n : ℕ) : n + ω = ω := - add_omega0 (nat_lt_omega0 n) - theorem principal_add_omega0 : Principal (· + ·) ω := principal_add_iff_add_left_eq_self.2 fun _ => add_omega0 @@ -388,7 +376,7 @@ theorem mul_lt_omega0_opow (c0 : 0 < c) (ha : a < ω ^ c) (hb : b < ω) : a * b · rcases ((isNormal_opow one_lt_omega0).limit_lt l).1 ha with ⟨x, hx, ax⟩ refine (mul_le_mul' (le_of_lt ax) (le_of_lt hb)).trans_lt ?_ rw [← opow_succ, opow_lt_opow_iff_right one_lt_omega0] - exact l.2 _ hx + exact l.succ_lt hx @[deprecated (since := "2024-09-30")] alias mul_lt_omega_opow := mul_lt_omega0_opow @@ -457,7 +445,7 @@ theorem mul_eq_opow_log_succ (ha : a ≠ 0) (hb : Principal (· * ·) b) (hb₂ have hbo₀ : b ^ log b a ≠ 0 := Ordinal.pos_iff_ne_zero.1 (opow_pos _ (zero_lt_one.trans hb₁)) apply (mul_le_mul_right' (le_of_lt (lt_mul_succ_div a hbo₀)) c).trans rw [mul_assoc, opow_succ] - refine mul_le_mul_left' (hb (hbl.2 _ ?_) hcb).le _ + refine mul_le_mul_left' (hb (hbl.succ_lt ?_) hcb).le _ rw [div_lt hbo₀, ← opow_succ] exact lt_opow_succ_log_self hb₁ _ · rw [opow_succ] diff --git a/Mathlib/SetTheory/Ordinal/Rank.lean b/Mathlib/SetTheory/Ordinal/Rank.lean index 1eb486c71b504..fb8b097d185a7 100644 --- a/Mathlib/SetTheory/Ordinal/Rank.lean +++ b/Mathlib/SetTheory/Ordinal/Rank.lean @@ -97,8 +97,6 @@ theorem IsWellFounded.rank_eq_typein (r) [IsWellOrder α r] : rank r = Ordinal.t namespace WellFounded -set_option linter.deprecated false - variable {r : α → α → Prop} (hwf : WellFounded r) /-- The rank of an element `a` under a well-founded relation `r` is defined inductively as the @@ -108,18 +106,22 @@ smallest ordinal greater than the ranks of all elements below it (i.e. elements noncomputable def rank (a : α) : Ordinal.{u} := (hwf.apply a).rank +set_option linter.deprecated false in @[deprecated IsWellFounded.rank_eq (since := "2024-09-07")] theorem rank_eq : hwf.rank a = ⨆ b : { b // r b a }, Order.succ (hwf.rank b) := (hwf.apply a).rank_eq +set_option linter.deprecated false in @[deprecated IsWellFounded.rank_lt_of_rel (since := "2024-09-07")] theorem rank_lt_of_rel (h : r a b) : hwf.rank a < hwf.rank b := Acc.rank_lt_of_rel _ h +set_option linter.deprecated false in @[deprecated WellFoundedLT.rank_strictMono (since := "2024-09-07")] theorem rank_strictMono [Preorder α] [WellFoundedLT α] : StrictMono (rank <| @wellFounded_lt α _ _) := fun _ _ => rank_lt_of_rel _ +set_option linter.deprecated false in @[deprecated WellFoundedGT.rank_strictAnti (since := "2024-09-07")] theorem rank_strictAnti [Preorder α] [WellFoundedGT α] : StrictAnti (rank <| @wellFounded_gt α _ _) := fun _ _ => rank_lt_of_rel wellFounded_gt diff --git a/Mathlib/SetTheory/Ordinal/Topology.lean b/Mathlib/SetTheory/Ordinal/Topology.lean index a1dd880e86d62..515769035484d 100644 --- a/Mathlib/SetTheory/Ordinal/Topology.lean +++ b/Mathlib/SetTheory/Ordinal/Topology.lean @@ -37,11 +37,11 @@ instance : TopologicalSpace Ordinal.{u} := Preorder.topology Ordinal.{u} instance : OrderTopology Ordinal.{u} := ⟨rfl⟩ theorem isOpen_singleton_iff : IsOpen ({a} : Set Ordinal) ↔ ¬IsLimit a := by - refine ⟨fun h ⟨h₀, hsucc⟩ => ?_, fun ha => ?_⟩ + refine ⟨fun h ha => ?_, fun ha => ?_⟩ · obtain ⟨b, c, hbc, hbc'⟩ := - (mem_nhds_iff_exists_Ioo_subset' ⟨0, Ordinal.pos_iff_ne_zero.2 h₀⟩ ⟨_, lt_succ a⟩).1 + (mem_nhds_iff_exists_Ioo_subset' ⟨0, ha.pos⟩ ⟨_, lt_succ a⟩).1 (h.mem_nhds rfl) - have hba := hsucc b hbc.1 + have hba := ha.succ_lt hbc.1 exact hba.ne (hbc' ⟨lt_succ b, hba.trans hbc.2⟩) · rcases zero_or_succ_or_limit a with (rfl | ⟨b, rfl⟩ | ha') · rw [← bot_eq_zero, ← Set.Iic_bot, ← Iio_succ] @@ -73,7 +73,7 @@ theorem nhds_eq_pure : 𝓝 a = pure a ↔ ¬IsLimit a := theorem isOpen_iff : IsOpen s ↔ ∀ o ∈ s, IsLimit o → ∃ a < o, Set.Ioo a o ⊆ s := by refine isOpen_iff_mem_nhds.trans <| forall₂_congr fun o ho => ?_ by_cases ho' : IsLimit o - · simp only [(nhdsBasis_Ioc ho'.1).mem_iff, ho', true_implies] + · simp only [(nhdsBasis_Ioc ho'.ne_zero).mem_iff, ho', true_implies] refine exists_congr fun a => and_congr_right fun ha => ?_ simp only [← Set.Ioo_insert_right ha, Set.insert_subset_iff, ho, true_and] · simp [nhds_eq_pure.2 ho', ho, ho'] @@ -216,8 +216,8 @@ theorem isNormal_iff_strictMono_and_continuous (f : Ordinal.{u} → Ordinal.{u}) suffices o ∈ f ⁻¹' Set.Iic a from Set.mem_preimage.1 this rw [mem_iff_iSup_of_isClosed (IsClosed.preimage h' (@isClosed_Iic _ _ _ _ a))] exact - ⟨_, toType_nonempty_iff_ne_zero.2 ho.1, typein (· < ·), fun i => h _ (typein_lt_self i), - sup_typein_limit ho.2⟩ + ⟨_, toType_nonempty_iff_ne_zero.2 ho.ne_zero, typein (· < ·), fun i => h _ (typein_lt_self i), + sup_typein_limit fun _ ↦ ho.succ_lt⟩ theorem enumOrd_isNormal_iff_isClosed (hs : ¬ BddAbove s) : IsNormal (enumOrd s) ↔ IsClosed s := by @@ -237,14 +237,14 @@ theorem enumOrd_isNormal_iff_isClosed (hs : ¬ BddAbove s) : · rw [isClosed_iff_bsup] at h suffices enumOrd s a ≤ bsup.{u, u} a fun b (_ : b < a) => enumOrd s b from this.trans (bsup_le H) - obtain ⟨b, hb⟩ := enumOrd_surjective hs (h ha.1 (fun b _ => enumOrd s b) + obtain ⟨b, hb⟩ := enumOrd_surjective hs (h ha.ne_zero (fun b _ => enumOrd s b) fun b _ => enumOrd_mem hs b) rw [← hb] apply Hs.monotone by_contra! hba apply (Hs (lt_succ b)).not_le rw [hb] - exact le_bsup.{u, u} _ _ (ha.2 _ hba) + exact le_bsup.{u, u} _ _ (ha.succ_lt hba) open Set Filter Set.Notation diff --git a/Mathlib/SetTheory/ZFC/Basic.lean b/Mathlib/SetTheory/ZFC/Basic.lean index a2b3354096bf0..535579e53318c 100644 --- a/Mathlib/SetTheory/ZFC/Basic.lean +++ b/Mathlib/SetTheory/ZFC/Basic.lean @@ -57,6 +57,7 @@ open Function (OfArity) is a family of pre-sets indexed by a type in `Type u`. The ZFC universe is defined as a quotient of this to ensure extensionality. -/ +@[pp_with_univ] inductive PSet : Type (u + 1) | mk (α : Type u) (A : α → PSet) : PSet @@ -443,8 +444,6 @@ def embed : PSet.{max (u + 1) v} := theorem lift_mem_embed : ∀ x : PSet.{u}, PSet.Lift.{u, max (u + 1) v} x ∈ embed.{u, v} := fun x => ⟨⟨x⟩, Equiv.rfl⟩ -set_option linter.deprecated false - /-- Function equivalence is defined so that `f ~ g` iff `∀ x y, x ~ y → f x ~ g y`. This extends to equivalence of `n`-ary functions. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] @@ -452,37 +451,44 @@ def Arity.Equiv : ∀ {n}, OfArity PSet.{u} PSet.{u} n → OfArity PSet.{u} PSet | 0, a, b => PSet.Equiv a b | _ + 1, a, b => ∀ x y : PSet, PSet.Equiv x y → Arity.Equiv (a x) (b y) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem Arity.equiv_const {a : PSet.{u}} : ∀ n, Arity.Equiv (OfArity.const PSet.{u} a n) (OfArity.const PSet.{u} a n) | 0 => Equiv.rfl | _ + 1 => fun _ _ _ => Arity.equiv_const _ +set_option linter.deprecated false in /-- `resp n` is the collection of n-ary functions on `PSet` that respect equivalence, i.e. when the inputs are equivalent the output is as well. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp (n) := { x : OfArity PSet.{u} PSet.{u} n // Arity.Equiv x x } +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] instance Resp.inhabited {n} : Inhabited (Resp n) := ⟨⟨OfArity.const _ default _, Arity.equiv_const _⟩⟩ +set_option linter.deprecated false in /-- The `n`-ary image of a `(n + 1)`-ary function respecting equivalence as a function respecting equivalence. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp.f {n} (f : Resp (n + 1)) (x : PSet) : Resp n := ⟨f.1 x, f.2 _ _ <| Equiv.refl x⟩ +set_option linter.deprecated false in /-- Function equivalence for functions respecting equivalence. See `PSet.Arity.Equiv`. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Resp.Equiv {n} (a b : Resp n) : Prop := Arity.Equiv a.1 b.1 +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02"), refl] protected theorem Resp.Equiv.refl {n} (a : Resp n) : Resp.Equiv a a := a.2 +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] protected theorem Resp.Equiv.euc : ∀ {n} {a b c : Resp n}, Resp.Equiv a b → Resp.Equiv c b → Resp.Equiv a c @@ -490,15 +496,18 @@ protected theorem Resp.Equiv.euc : | n + 1, a, b, c, hab, hcb => fun x y h => @Resp.Equiv.euc n (a.f x) (b.f y) (c.f y) (hab _ _ h) (hcb _ _ <| PSet.Equiv.refl y) +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02"), symm] protected theorem Resp.Equiv.symm {n} {a b : Resp n} : Resp.Equiv a b → Resp.Equiv b a := (Resp.Equiv.refl b).euc +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02"), trans] protected theorem Resp.Equiv.trans {n} {x y z : Resp n} (h1 : Resp.Equiv x y) (h2 : Resp.Equiv y z) : Resp.Equiv x z := h1.euc h2.symm +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] instance Resp.setoid {n} : Setoid (Resp n) := ⟨Resp.Equiv, Resp.Equiv.refl, Resp.Equiv.symm, Resp.Equiv.trans⟩ @@ -507,6 +516,7 @@ end PSet /-- The ZFC universe of sets consists of the type of pre-sets, quotiented by extensional equivalence. -/ +@[pp_with_univ] def ZFSet : Type (u + 1) := Quotient PSet.setoid.{u} @@ -606,10 +616,9 @@ end ZFSet namespace PSet -set_option linter.deprecated false - namespace Resp +set_option linter.deprecated false in /-- Helper function for `PSet.eval`. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def evalAux : @@ -625,11 +634,13 @@ def evalAux : (@Quotient.ind _ _ fun q => F b q = F c q) fun z => evalAux.2 (Resp.f b z) (Resp.f c z) (h _ _ (PSet.Equiv.refl z))⟩ +set_option linter.deprecated false in /-- An equivalence-respecting function yields an n-ary ZFC set function. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def eval (n) : Resp n → OfArity ZFSet.{u} ZFSet.{u} n := evalAux.1 +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem eval_val {n f x} : (@eval (n + 1) f : ZFSet → OfArity ZFSet ZFSet n) ⟦x⟧ = eval n (Resp.f f x) := @@ -637,6 +648,7 @@ theorem eval_val {n f x} : end Resp +set_option linter.deprecated false in /-- A set function is "definable" if it is the image of some n-ary pre-set function. This isn't exactly definability, but is useful as a sufficient condition for functions that have a computable image. -/ @@ -647,17 +659,20 @@ class inductive Definable (n) : OfArity ZFSet.{u} ZFSet.{u} n → Type (u + 1) attribute [deprecated "No deprecation message was provided." (since := "2024-09-02"), instance] Definable.mk +set_option linter.deprecated false in /-- The evaluation of a function respecting equivalence is definable, by that same function. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Definable.EqMk {n} (f) : ∀ {s : OfArity ZFSet.{u} ZFSet.{u} n} (_ : Resp.eval _ f = s), Definable n s | _, rfl => ⟨f⟩ +set_option linter.deprecated false in /-- Turns a definable function into a function that respects equivalence. -/ @[deprecated "No deprecation message was provided." (since := "2024-09-02")] def Definable.Resp {n} : ∀ (s : OfArity ZFSet.{u} ZFSet.{u} n) [Definable n s], Resp n | _, ⟨f⟩ => f +set_option linter.deprecated false in @[deprecated "No deprecation message was provided." (since := "2024-09-02")] theorem Definable.eq {n} : ∀ (s : OfArity ZFSet.{u} ZFSet.{u} n) [H : Definable n s], (@Definable.Resp n s H).eval _ = s @@ -1333,6 +1348,7 @@ end ZFSet We define `Class` as `Set ZFSet`, as this allows us to get many instances automatically. However, in practice, we treat it as (the definitionally equal) `ZFSet → Prop`. This means, the preferred way to state that `x : ZFSet` belongs to `A : Class` is to write `A x`. -/ +@[pp_with_univ] def Class := Set ZFSet deriving HasSubset, EmptyCollection, Nonempty, Union, Inter, HasCompl, SDiff diff --git a/Mathlib/SetTheory/ZFC/Ordinal.lean b/Mathlib/SetTheory/ZFC/Ordinal.lean index bd816b21e5dac..43a8b4f282040 100644 --- a/Mathlib/SetTheory/ZFC/Ordinal.lean +++ b/Mathlib/SetTheory/ZFC/Ordinal.lean @@ -34,7 +34,9 @@ variable {x y z : ZFSet.{u}} namespace ZFSet -/-- A transitive set is one where every element is a subset. -/ +/-- A transitive set is one where every element is a subset. + +This is equivalent to being an infinite-open interval in the transitive closure of membership. -/ def IsTransitive (x : ZFSet) : Prop := ∀ y ∈ x, y ⊆ x @@ -56,11 +58,13 @@ protected theorem IsTransitive.inter (hx : x.IsTransitive) (hy : y.IsTransitive) rw [mem_inter] at hz ⊢ exact ⟨hx.mem_trans hw hz.1, hy.mem_trans hw hz.2⟩ +/-- The union of a transitive set is transitive. -/ protected theorem IsTransitive.sUnion (h : x.IsTransitive) : (⋃₀ x : ZFSet).IsTransitive := fun y hy z hz => by rcases mem_sUnion.1 hy with ⟨w, hw, hw'⟩ exact mem_sUnion_of_mem hz (h.mem_trans hw' hw) +/-- The union of transitive sets is transitive. -/ theorem IsTransitive.sUnion' (H : ∀ y ∈ x, IsTransitive y) : (⋃₀ x : ZFSet).IsTransitive := fun y hy z hz => by rcases mem_sUnion.1 hy with ⟨w, hw, hw'⟩ diff --git a/Mathlib/Tactic/Abel.lean b/Mathlib/Tactic/Abel.lean index 4002862603dbc..0326607cfdb06 100644 --- a/Mathlib/Tactic/Abel.lean +++ b/Mathlib/Tactic/Abel.lean @@ -436,14 +436,14 @@ The core of `abel_nf`, which rewrites the expression `e` into `abel` normal form -/ partial def abelNFCore (s : IO.Ref AtomM.State) (cfg : AbelNF.Config) (e : Expr) : MetaM Simp.Result := do - let ctx := { - simpTheorems := #[← Elab.Tactic.simpOnlyBuiltins.foldlM (·.addConst ·) {}] - congrTheorems := ← getSimpCongrTheorems } + let ctx ← Simp.mkContext + (simpTheorems := #[← Elab.Tactic.simpOnlyBuiltins.foldlM (·.addConst ·) {}]) + (congrTheorems := ← getSimpCongrTheorems) let simp ← match cfg.mode with | .raw => pure pure | .term => let thms := [``term_eq, ``termg_eq, ``add_zero, ``one_nsmul, ``one_zsmul, ``zsmul_zero] - let ctx' := { ctx with simpTheorems := #[← thms.foldlM (·.addConst ·) {:_}] } + let ctx' := ctx.setSimpTheorems #[← thms.foldlM (·.addConst ·) {:_}] pure fun r' : Simp.Result ↦ do r'.mkEqTrans (← Simp.main r'.expr ctx' (methods := ← Lean.Meta.Simp.mkDefaultMethods)).1 let rec diff --git a/Mathlib/Tactic/CC/Addition.lean b/Mathlib/Tactic/CC/Addition.lean index 402aa77e105b8..8548c1ad7b0c7 100644 --- a/Mathlib/Tactic/CC/Addition.lean +++ b/Mathlib/Tactic/CC/Addition.lean @@ -390,7 +390,7 @@ partial def mkCongrProofCore (lhs rhs : Expr) (heqProofs : Bool) : CCM Expr := d guard (kindsIt[0]! matches .eq) let some p ← getEqProof (lhsArgs[i]'hi.2) (rhsArgs[i]'(ha.symm ▸ hi.2)) | failure lemmaArgs := lemmaArgs.push p - kindsIt := kindsIt.eraseIdx 0 + kindsIt := kindsIt.eraseIdx! 0 let mut r := mkAppN specLemma.proof lemmaArgs if specLemma.heqResult && !heqProofs then r ← mkAppM ``eq_of_heq #[r] @@ -1748,7 +1748,7 @@ def propagateProjectionConstructor (p c : Expr) : CCM Unit := do unless ← pureIsDefEq (← inferType (pArgs[mkidx]'h)) (← inferType c) do return /- Create new projection application using c (e.g., `(x, y).fst`), and internalize it. The internalizer will add the new equality. -/ - let pArgs := pArgs.set ⟨mkidx, h⟩ c + let pArgs := pArgs.set mkidx c let newP := mkAppN pFn pArgs internalizeCore newP none else diff --git a/Mathlib/Tactic/CancelDenoms/Core.lean b/Mathlib/Tactic/CancelDenoms/Core.lean index b8ada93499ee9..db9ba05cb8083 100644 --- a/Mathlib/Tactic/CancelDenoms/Core.lean +++ b/Mathlib/Tactic/CancelDenoms/Core.lean @@ -231,7 +231,7 @@ def derive (e : Expr) : MetaM (ℕ × Expr) := do trace[CancelDenoms] "e = {e}" let eSimp ← simpOnlyNames (config := Simp.neutralConfig) deriveThms e trace[CancelDenoms] "e simplified = {eSimp.expr}" - let eSimpNormNum ← Mathlib.Meta.NormNum.deriveSimp {} false eSimp.expr + let eSimpNormNum ← Mathlib.Meta.NormNum.deriveSimp (← Simp.mkContext) false eSimp.expr trace[CancelDenoms] "e norm_num'd = {eSimpNormNum.expr}" let (n, t) := findCancelFactor eSimpNormNum.expr let ⟨u, tp, e⟩ ← inferTypeQ' eSimpNormNum.expr diff --git a/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean b/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean index 887a1d5d3c240..8aeea85868649 100644 --- a/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean +++ b/Mathlib/Tactic/CategoryTheory/BicategoryCoherence.lean @@ -115,7 +115,7 @@ def bicategory_coherence (g : MVarId) : TermElabM Unit := g.withContext do let thms := [``BicategoricalCoherence.iso, ``Iso.trans, ``Iso.symm, ``Iso.refl, ``Bicategory.whiskerRightIso, ``Bicategory.whiskerLeftIso].foldl (·.addDeclToUnfoldCore ·) {} - let (ty, _) ← dsimp (← g.getType) { simpTheorems := #[thms] } + let (ty, _) ← dsimp (← g.getType) (← Simp.mkContext (simpTheorems := #[thms])) let some (_, lhs, rhs) := (← whnfR ty).eq? | exception g "Not an equation of morphisms." let lift_lhs ← mkLiftMap₂LiftExpr lhs let lift_rhs ← mkLiftMap₂LiftExpr rhs diff --git a/Mathlib/Tactic/CategoryTheory/Coherence.lean b/Mathlib/Tactic/CategoryTheory/Coherence.lean index e7e501d21c186..d136aaa42960b 100644 --- a/Mathlib/Tactic/CategoryTheory/Coherence.lean +++ b/Mathlib/Tactic/CategoryTheory/Coherence.lean @@ -124,7 +124,7 @@ def monoidal_coherence (g : MVarId) : TermElabM Unit := g.withContext do let thms := [``MonoidalCoherence.iso, ``Iso.trans, ``Iso.symm, ``Iso.refl, ``MonoidalCategory.whiskerRightIso, ``MonoidalCategory.whiskerLeftIso].foldl (·.addDeclToUnfoldCore ·) {} - let (ty, _) ← dsimp (← g.getType) { simpTheorems := #[thms] } + let (ty, _) ← dsimp (← g.getType) (← Simp.mkContext (simpTheorems := #[thms])) let some (_, lhs, rhs) := (← whnfR ty).eq? | exception g "Not an equation of morphisms." let projectMap_lhs ← mkProjectMapExpr lhs let projectMap_rhs ← mkProjectMapExpr rhs diff --git a/Mathlib/Tactic/CategoryTheory/Elementwise.lean b/Mathlib/Tactic/CategoryTheory/Elementwise.lean index 4a108c00b9927..656aab46bfe30 100644 --- a/Mathlib/Tactic/CategoryTheory/Elementwise.lean +++ b/Mathlib/Tactic/CategoryTheory/Elementwise.lean @@ -88,7 +88,7 @@ def elementwiseExpr (src : Name) (type pf : Expr) (simpSides := true) : 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 ctx ← Simp.Context.mkDefault let (ty', eqPf'') ← simpEq (fun e => return (← simp e ctx).1) (← inferType eqPf') eqPf' -- check that it's not a simp-trivial equality: forallTelescope ty' fun _ ty' => do diff --git a/Mathlib/Tactic/Common.lean b/Mathlib/Tactic/Common.lean index 3c61c4a884912..94a9e57234ef3 100644 --- a/Mathlib/Tactic/Common.lean +++ b/Mathlib/Tactic/Common.lean @@ -112,6 +112,7 @@ import Mathlib.Tactic.Widget.Conv import Mathlib.Tactic.WLOG import Mathlib.Util.AssertExists import Mathlib.Util.CountHeartbeats +import Mathlib.Util.TransImports import Mathlib.Util.WhatsNew /-! diff --git a/Mathlib/Tactic/DeprecateTo.lean b/Mathlib/Tactic/DeprecateTo.lean index 4f8d8522506e0..a374440b2c34e 100644 --- a/Mathlib/Tactic/DeprecateTo.lean +++ b/Mathlib/Tactic/DeprecateTo.lean @@ -107,7 +107,7 @@ Technically, the command also take an optional `String` argument to fill in the However, its use is mostly intended for debugging purposes, where having a variable date would make tests time-dependent. -/ -elab tk:"deprecate to " id:ident* dat:(ppSpace str ppSpace)? ppLine cmd:command : command => do +elab tk:"deprecate" "to" id:ident* dat:(ppSpace str ppSpace)? ppLine cmd:command : command => do let oldEnv ← getEnv try elabCommand cmd diff --git a/Mathlib/Tactic/DeriveTraversable.lean b/Mathlib/Tactic/DeriveTraversable.lean index 2ad019823e4bd..54a52f0b432bf 100644 --- a/Mathlib/Tactic/DeriveTraversable.lean +++ b/Mathlib/Tactic/DeriveTraversable.lean @@ -274,7 +274,7 @@ def deriveLawfulFunctor (m : MVarId) : TermElabM Unit := do if b then let hs ← getPropHyps s ← hs.foldlM (fun s f => f.getDecl >>= fun d => s.add (.fvar f) #[] d.toExpr) s - return { simpTheorems := #[s] } + Simp.mkContext (simpTheorems := #[s]) let .app (.app (.const ``LawfulFunctor _) F) _ ← m.getType >>= instantiateMVars | failure let some n := F.getAppFn.constName? | failure let [mcn, mim, mcm] ← m.applyConst ``LawfulFunctor.mk | failure @@ -435,7 +435,7 @@ def simpFunctorGoal (m : MVarId) (s : Simp.Context) (simprocs : Simp.SimprocsArr MetaM (Option (Array FVarId × MVarId) × Simp.Stats) := do let some e ← getSimpExtension? `functor_norm | failure let s' ← e.getTheorems - simpGoal m { s with simpTheorems := s.simpTheorems.push s' } simprocs discharge? simplifyTarget + simpGoal m (s.setSimpTheorems (s.simpTheorems.push s')) simprocs discharge? simplifyTarget fvarIdsToSimp stats /-- Run the following tactic: @@ -451,7 +451,7 @@ def traversableLawStarter (m : MVarId) (n : Name) (s : MetaM Simp.Context) (fun s n => s.addDeclToUnfold n) ({} : SimpTheorems) let (fi, m) ← m.intros m.withContext do - if let (some m, _) ← dsimpGoal m { simpTheorems := #[s'] } then + if let (some m, _) ← dsimpGoal m (← Simp.mkContext (simpTheorems := #[s'])) then let ma ← m.induction fi.back! (mkRecName n) ma.forM fun is => is.mvarId.withContext do @@ -467,9 +467,7 @@ def deriveLawfulTraversable (m : MVarId) : TermElabM Unit := do if b then let hs ← getPropHyps s ← hs.foldlM (fun s f => f.getDecl >>= fun d => s.add (.fvar f) #[] d.toExpr) s - pure <| - { config := { failIfUnchanged := false, unfoldPartialApp := true }, - simpTheorems := #[s] } + Simp.mkContext { failIfUnchanged := false, unfoldPartialApp := true } (simpTheorems := #[s]) let .app (.app (.const ``LawfulTraversable _) F) _ ← m.getType >>= instantiateMVars | failure let some n := F.getAppFn.constName? | failure let [mit, mct, mtmi, mn] ← m.applyConst ``LawfulTraversable.mk | failure diff --git a/Mathlib/Tactic/FBinop.lean b/Mathlib/Tactic/FBinop.lean index 3eb83fec8d8d6..8e58cb0849763 100644 --- a/Mathlib/Tactic/FBinop.lean +++ b/Mathlib/Tactic/FBinop.lean @@ -185,12 +185,12 @@ private def toExprCore (t : Tree) : TermElabM Expr := do | .term _ trees e => modifyInfoState (fun s => { s with trees := s.trees ++ trees }); return e | .binop ref f lhs rhs => - withRef ref <| withInfoContext' ref (mkInfo := mkTermInfo .anonymous ref) do + withRef ref <| withTermInfoContext' .anonymous ref do let lhs ← toExprCore lhs let mut rhs ← toExprCore rhs mkBinOp f lhs rhs | .macroExpansion macroName stx stx' nested => - withRef stx <| withInfoContext' stx (mkInfo := mkTermInfo macroName stx) do + withRef stx <| withTermInfoContext' macroName stx do withMacroExpansion stx stx' do toExprCore nested diff --git a/Mathlib/Tactic/FieldSimp.lean b/Mathlib/Tactic/FieldSimp.lean index b401457965534..a3e7f13ab83a1 100644 --- a/Mathlib/Tactic/FieldSimp.lean +++ b/Mathlib/Tactic/FieldSimp.lean @@ -61,26 +61,27 @@ partial def discharge (prop : Expr) : SimpM (Option Expr) := if let some pf := pf? then return some pf -- Discharge strategy 4: Use the simplifier - let ctx ← readThe Simp.Context - let stats : Simp.Stats := { (← get) with } - - -- Porting note: mathlib3's analogous field_simp discharger `field_simp.ne_zero` - -- does not explicitly call `simp` recursively like this. It's unclear to me - -- whether this is because - -- 1) Lean 3 simp dischargers automatically call `simp` recursively. (Do they?), - -- 2) mathlib3 norm_num1 is able to handle any needed discharging, or - -- 3) some other reason? - let ⟨simpResult, stats'⟩ ← - simp prop { ctx with dischargeDepth := ctx.dischargeDepth + 1 } #[(← Simp.getSimprocs)] - discharge stats - set { (← get) with usedTheorems := stats'.usedTheorems, diag := stats'.diag } - if simpResult.expr.isConstOf ``True then - try - return some (← mkOfEqTrue (← simpResult.getProof)) - catch _ => + Simp.withIncDischargeDepth do + let ctx ← readThe Simp.Context + let stats : Simp.Stats := { (← get) with } + + -- Porting note: mathlib3's analogous field_simp discharger `field_simp.ne_zero` + -- does not explicitly call `simp` recursively like this. It's unclear to me + -- whether this is because + -- 1) Lean 3 simp dischargers automatically call `simp` recursively. (Do they?), + -- 2) mathlib3 norm_num1 is able to handle any needed discharging, or + -- 3) some other reason? + let ⟨simpResult, stats'⟩ ← + simp prop ctx #[(← Simp.getSimprocs)] + discharge stats + set { (← get) with usedTheorems := stats'.usedTheorems, diag := stats'.diag } + if simpResult.expr.isConstOf ``True then + try + return some (← mkOfEqTrue (← simpResult.getProof)) + catch _ => + return none + else return none - else - return none @[inherit_doc discharge] elab "field_simp_discharge" : tactic => wrapSimpDischarger Mathlib.Tactic.FieldSimp.discharge @@ -175,11 +176,10 @@ elab_rules : tactic let some ext ← getSimpExtension? `field_simps | throwError "field_simps not found" let thms ← ext.getTheorems - let ctx : Simp.Context := { - simpTheorems := #[thms, thms0] - congrTheorems := ← getSimpCongrTheorems - config := cfg - } + let ctx ← Simp.mkContext cfg + (simpTheorems := #[thms, thms0]) + (congrTheorems := ← getSimpCongrTheorems) + let mut r ← elabSimpArgs (sa.getD ⟨.missing⟩) ctx (simprocs := {}) (eraseLocal := false) .simp if r.starArg then r ← do @@ -189,7 +189,7 @@ elab_rules : tactic for h in hs do unless simpTheorems.isErased (.fvar h) do simpTheorems ← simpTheorems.addTheorem (.fvar h) (← h.getDecl).toExpr - let ctx := { ctx with simpTheorems } + let ctx := ctx.setSimpTheorems simpTheorems pure { ctx, simprocs := {} } _ ← simpLocation r.ctx {} dis loc diff --git a/Mathlib/Tactic/FunProp/Attr.lean b/Mathlib/Tactic/FunProp/Attr.lean index 55a876dcd0943..5566c0f969179 100644 --- a/Mathlib/Tactic/FunProp/Attr.lean +++ b/Mathlib/Tactic/FunProp/Attr.lean @@ -27,7 +27,6 @@ initialize funPropAttr : Unit ← add := fun declName _stx attrKind => discard <| MetaM.run do let info ← getConstInfo declName - forallTelescope info.type fun _ b => do if b.isProp then addFunPropDecl declName diff --git a/Mathlib/Tactic/FunProp/ContDiff.lean b/Mathlib/Tactic/FunProp/ContDiff.lean index 037d1812296a5..b5325b5527b64 100644 --- a/Mathlib/Tactic/FunProp/ContDiff.lean +++ b/Mathlib/Tactic/FunProp/ContDiff.lean @@ -61,7 +61,7 @@ variable {K : Type*} [NontriviallyNormedField K] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace K E] variable {s} -theorem ContDiffOn.div' [CompleteSpace K] {f g : E → K} {n} (hf : ContDiffOn K n f s) +theorem ContDiffOn.div' {f g : E → K} {n} (hf : ContDiffOn K n f s) (hg : ContDiffOn K n g s) (h₀ : ∀ x ∈ s, g x ≠ 0) : ContDiffOn K n (fun x => f x / g x) s := ContDiffOn.div hf hg h₀ diff --git a/Mathlib/Tactic/FunProp/Core.lean b/Mathlib/Tactic/FunProp/Core.lean index 9f84b5b2c1371..105bd3beea9c0 100644 --- a/Mathlib/Tactic/FunProp/Core.lean +++ b/Mathlib/Tactic/FunProp/Core.lean @@ -324,9 +324,7 @@ def applyMorRules (funPropDecl : FunPropDecl) (e : Expr) (fData : FunctionData) applyCompRule funPropDecl e f g funProp | .exact => - let ext := morTheoremsExt.getState (← getEnv) - let candidates ← ext.theorems.getMatchWithScore e false { iota := false, zeta := false } - let candidates := candidates.map (·.1) |>.flatten + let candidates ← getMorphismTheorems e trace[Meta.Tactic.fun_prop] "candidate morphism theorems: {← candidates.mapM fun c => ppOrigin (.decl c.thmName)}" @@ -343,9 +341,7 @@ def applyTransitionRules (e : Expr) (funProp : Expr → FunPropM (Option Result) FunPropM (Option Result) := do withIncreasedTransitionDepth do - let ext := transitionTheoremsExt.getState (← getEnv) - let candidates ← ext.theorems.getMatchWithScore e false { iota := false, zeta := false } - let candidates := candidates.map (·.1) |>.flatten + let candidates ← getTransitionTheorems e trace[Meta.Tactic.fun_prop] "candidate transition theorems: {← candidates.mapM fun c => ppOrigin (.decl c.thmName)}" @@ -433,7 +429,7 @@ def getLocalTheorems (funPropDecl : FunPropDecl) (funOrigin : Origin) let .some (decl,f) ← getFunProp? b | return none unless decl.funPropName = funPropDecl.funPropName do return none - let .data fData ← getFunctionData? f (← unfoldNamePred) {zeta := false, zetaDelta := false} + let .data fData ← getFunctionData? f (← unfoldNamePred) | return none unless (fData.getFnOrigin == funOrigin) do return none @@ -672,7 +668,7 @@ mutual let e' := e.setArg funPropDecl.funArgId b funProp (← mkLambdaFVars xs e') - match ← getFunctionData? f (← unfoldNamePred) {zeta := false, zetaDelta := false} with + match ← getFunctionData? f (← unfoldNamePred) with | .letE f => trace[Debug.Meta.Tactic.fun_prop] "let case on {← ppExpr f}" let e := e.setArg funPropDecl.funArgId f -- update e with reduced f diff --git a/Mathlib/Tactic/FunProp/Decl.lean b/Mathlib/Tactic/FunProp/Decl.lean index d91b7a71fec56..eecfb35cb2fdd 100644 --- a/Mathlib/Tactic/FunProp/Decl.lean +++ b/Mathlib/Tactic/FunProp/Decl.lean @@ -61,7 +61,7 @@ def addFunPropDecl (declName : Name) : MetaM Unit := do let lvls := info.levelParams.map (fun l => Level.param l) let e := mkAppN (.const declName lvls) xs - let path ← DiscrTree.mkPath e {} + let path ← DiscrTree.mkPath e -- find the argument position of the function `f` in `P f` let mut .some funArgId ← (xs.zip bi).findIdxM? fun (x,bi) => do @@ -88,7 +88,7 @@ the function it talks about. -/ def getFunProp? (e : Expr) : MetaM (Option (FunPropDecl × Expr)) := do let ext := funPropDeclsExt.getState (← getEnv) - let decls ← ext.decls.getMatch e {} + let decls ← ext.decls.getMatch e (← read) if decls.size = 0 then return none diff --git a/Mathlib/Tactic/FunProp/FunctionData.lean b/Mathlib/Tactic/FunProp/FunctionData.lean index c5f3356767d0f..8c36005b51303 100644 --- a/Mathlib/Tactic/FunProp/FunctionData.lean +++ b/Mathlib/Tactic/FunProp/FunctionData.lean @@ -117,8 +117,9 @@ def MaybeFunctionData.get (fData : MaybeFunctionData) : MetaM Expr := /-- Get `FunctionData` for `f`. -/ def getFunctionData? (f : Expr) - (unfoldPred : Name → Bool := fun _ => false) (cfg : WhnfCoreConfig := {}) : + (unfoldPred : Name → Bool := fun _ => false) : MetaM MaybeFunctionData := do + withConfig (fun cfg => { cfg with zeta := false, zetaDelta := false }) do let unfold := fun e : Expr => do if let .some n := e.getAppFn'.constName? then @@ -130,7 +131,7 @@ def getFunctionData? (f : Expr) | throwError m!"fun_prop bug: function expected, got `{f} : {← inferType f}, \ type ctor {(← inferType f).ctorName}" withLocalDeclD xName xType fun x => do - let fx' := (← Mor.whnfPred (f.beta #[x]).eta unfold cfg) |> headBetaThroughLet + let fx' := (← Mor.whnfPred (f.beta #[x]).eta unfold) |> headBetaThroughLet let f' ← mkLambdaFVars #[x] fx' match fx' with | .letE .. => return .letE f' diff --git a/Mathlib/Tactic/FunProp/Mor.lean b/Mathlib/Tactic/FunProp/Mor.lean index 1b27bf7755713..b7cf3ec7c15e2 100644 --- a/Mathlib/Tactic/FunProp/Mor.lean +++ b/Mathlib/Tactic/FunProp/Mor.lean @@ -63,14 +63,14 @@ can specify which when to unfold definitions. For example calling this on `coe (f a) b` will put `f` in weak normal head form instead of `coe`. -/ -partial def whnfPred (e : Expr) (pred : Expr → MetaM Bool) (cfg : WhnfCoreConfig := {}) : +partial def whnfPred (e : Expr) (pred : Expr → MetaM Bool) : MetaM Expr := do whnfEasyCases e fun e => do - let e ← whnfCore e cfg + let e ← whnfCore e if let .some ⟨coe,f,x⟩ ← isMorApp? e then - let f ← whnfPred f pred cfg - if cfg.zeta then + let f ← whnfPred f pred + if (← getConfig).zeta then return (coe.app f).app x else return ← letTelescope f fun xs f' => @@ -78,7 +78,7 @@ partial def whnfPred (e : Expr) (pred : Expr → MetaM Bool) (cfg : WhnfCoreConf if (← pred e) then match (← unfoldDefinition? e) with - | some e => whnfPred e pred cfg + | some e => whnfPred e pred | none => return e else return e @@ -88,8 +88,8 @@ Weak normal head form of an expression involving morphism applications. For example calling this on `coe (f a) b` will put `f` in weak normal head form instead of `coe`. -/ -def whnf (e : Expr) (cfg : WhnfCoreConfig := {}) : MetaM Expr := - whnfPred e (fun _ => return false) cfg +def whnf (e : Expr) : MetaM Expr := + whnfPred e (fun _ => return false) /-- Argument of morphism application that stores corresponding coercion if necessary -/ diff --git a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean index 46b53085e8011..439560f236c24 100644 --- a/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean +++ b/Mathlib/Tactic/FunProp/RefinedDiscrTree.lean @@ -438,23 +438,23 @@ where | _ => failure /-- Reduction procedure for the `RefinedDiscrTree` indexing. -/ -partial def reduce (e : Expr) (config : WhnfCoreConfig) : MetaM Expr := do - let e ← whnfCore e config +partial def reduce (e : Expr) : MetaM Expr := do + let e ← whnfCore e match (← unfoldDefinition? e) with - | some e => reduce e config + | some e => reduce e | none => match e.etaExpandedStrict? with - | some e => reduce e config + | some e => reduce e | none => return e /-- Repeatedly apply reduce while stripping lambda binders and introducing their variables -/ @[specialize] partial def lambdaTelescopeReduce {m} [Monad m] [MonadLiftT MetaM m] [MonadControlT MetaM m] - [Nonempty α] (e : Expr) (fvars : List FVarId) (config : WhnfCoreConfig) + [Nonempty α] (e : Expr) (fvars : List FVarId) (k : Expr → List FVarId → m α) : m α := do - match ← reduce e config with + match ← reduce e with | .lam n d b bi => withLocalDecl n bi d fun fvar => - lambdaTelescopeReduce (b.instantiate1 fvar) (fvar.fvarId! :: fvars) config k + lambdaTelescopeReduce (b.instantiate1 fvar) (fvar.fvarId! :: fvars) k | e => k e fvars @@ -492,7 +492,6 @@ private structure Context where bvars : List FVarId := [] /-- Variables that come from a lambda that has been removed via η-reduction. -/ forbiddenVars : List FVarId := [] - config : WhnfCoreConfig fvarInContext : FVarId → Bool /-- Return for each argument whether it should be ignored. -/ @@ -633,7 +632,7 @@ private def withLams {m} [Monad m] [MonadWithReader Context m] /-- Return the encoding of `e` as a `DTExpr`. If `root = false`, then `e` is a strict sub expression of the original expression. -/ partial def mkDTExprAux (e : Expr) (root : Bool) : ReaderT Context MetaM DTExpr := do - lambdaTelescopeReduce e [] (← read).config fun e lambdas => + lambdaTelescopeReduce e [] fun e lambdas => e.withApp fun fn args => do let argDTExpr (arg : Expr) (ignore : Bool) : ReaderT Context MetaM DTExpr := @@ -755,7 +754,7 @@ def cacheEtaPossibilities (e original : Expr) (lambdas : List FVarId) /-- Return all encodings of `e` as a `DTExpr`, taking possible η-reductions into account. If `root = false`, then `e` is a strict sub expression of the original expression. -/ partial def mkDTExprsAux (original : Expr) (root : Bool) : M DTExpr := do - lambdaTelescopeReduce original [] (← read).config fun e lambdas => do + lambdaTelescopeReduce original [] fun e lambdas => do if !root then if let .const n _ := e.getAppFn then @@ -849,16 +848,16 @@ Warning: to account for potential η-reductions of `e`, use `mkDTExprs` instead. The argument `fvarInContext` allows you to specify which free variables in `e` will still be in the context when the `RefinedDiscrTree` is being used for lookup. It should return true only if the `RefinedDiscrTree` is built and used locally. -/ -def mkDTExpr (e : Expr) (config : WhnfCoreConfig) +def mkDTExpr (e : Expr) (fvarInContext : FVarId → Bool := fun _ => false) : MetaM DTExpr := - withReducible do (MkDTExpr.mkDTExprAux e true |>.run {config, fvarInContext}) + withReducible do (MkDTExpr.mkDTExprAux e true |>.run {fvarInContext}) /-- Similar to `mkDTExpr`. Return all encodings of `e` as a `DTExpr`, taking potential further η-reductions into account. -/ -def mkDTExprs (e : Expr) (config : WhnfCoreConfig) (onlySpecific : Bool) +def mkDTExprs (e : Expr) (onlySpecific : Bool) (fvarInContext : FVarId → Bool := fun _ => false) : MetaM (List DTExpr) := withReducible do - let es ← (MkDTExpr.mkDTExprsAux e true).run' {} |>.run {config, fvarInContext} + let es ← (MkDTExpr.mkDTExprsAux e true).run' {} |>.run {fvarInContext} return if onlySpecific then es.filter (·.isSpecific) else es @@ -875,7 +874,7 @@ where loop (i : Nat) : Array α := if h : i < vs.size then if v == vs[i] then - vs.set ⟨i,h⟩ v + vs.set i v else loop (i+1) else @@ -932,18 +931,18 @@ It should return true only if the `RefinedDiscrTree` is built and used locally. if `onlySpecific := true`, then we filter out the patterns `*` and `Eq * * *`. -/ def insert [BEq α] (d : RefinedDiscrTree α) (e : Expr) (v : α) - (onlySpecific : Bool := true) (config : WhnfCoreConfig := {}) - (fvarInContext : FVarId → Bool := fun _ => false) : MetaM (RefinedDiscrTree α) := do - let keys ← mkDTExprs e config onlySpecific fvarInContext + (onlySpecific : Bool := true) (fvarInContext : FVarId → Bool := fun _ => false) : + MetaM (RefinedDiscrTree α) := do + let keys ← mkDTExprs e onlySpecific fvarInContext return keys.foldl (insertDTExpr · · v) d /-- Insert the value `vLhs` at index `lhs`, and if `rhs` is indexed differently, then also insert the value `vRhs` at index `rhs`. -/ def insertEqn [BEq α] (d : RefinedDiscrTree α) (lhs rhs : Expr) (vLhs vRhs : α) - (onlySpecific : Bool := true) (config : WhnfCoreConfig := {}) - (fvarInContext : FVarId → Bool := fun _ => false) : MetaM (RefinedDiscrTree α) := do - let keysLhs ← mkDTExprs lhs config onlySpecific fvarInContext - let keysRhs ← mkDTExprs rhs config onlySpecific fvarInContext + (onlySpecific : Bool := true) (fvarInContext : FVarId → Bool := fun _ => false) : + MetaM (RefinedDiscrTree α) := do + let keysLhs ← mkDTExprs lhs onlySpecific fvarInContext + let keysRhs ← mkDTExprs rhs onlySpecific fvarInContext let d := keysLhs.foldl (insertDTExpr · · vLhs) d if @List.beq _ ⟨DTExpr.eqv⟩ keysLhs keysRhs then return d @@ -967,7 +966,6 @@ def findKey (children : Array (Key × Trie α)) (k : Key) : Option (Trie α) := private structure Context where unify : Bool - config : WhnfCoreConfig private structure State where /-- Score representing how good the match is. -/ @@ -981,9 +979,9 @@ private structure State where private abbrev M := ReaderT Context <| StateListM State /-- Return all values from `x` in an array, together with their scores. -/ -private def M.run (unify : Bool) (config : WhnfCoreConfig) (x : M (Trie α)) : +private def M.run (unify : Bool) (x : M (Trie α)) : Array (Array α × Nat) := - ((x.run { unify, config }).run {}).toArray.map (fun (t, s) => (t.values!, s.score)) + ((x.run { unify }).run {}).toArray.map (fun (t, s) => (t.values!, s.score)) /-- Increment the score by `n`. -/ private def incrementScore (n : Nat) : M Unit := @@ -1076,7 +1074,7 @@ mutual end private partial def getMatchWithScoreAux (d : RefinedDiscrTree α) (e : DTExpr) (unify : Bool) - (config : WhnfCoreConfig) (allowRootStar : Bool := false) : Array (Array α × Nat) := (do + (allowRootStar : Bool := false) : Array (Array α × Nat) := (do if e matches .star _ then guard allowRootStar d.root.foldl (init := failure) fun x k c => (do @@ -1090,7 +1088,7 @@ private partial def getMatchWithScoreAux (d : RefinedDiscrTree α) (e : DTExpr) guard allowRootStar let some c := d.root.find? (.star 0) | failure return c - ).run unify config + ).run unify end GetUnify @@ -1106,22 +1104,22 @@ This is for when you don't want to instantiate metavariables in `e`. If `allowRootStar := false`, then we don't allow `e` or the matched key in `d` to be a star pattern. -/ def getMatchWithScore (d : RefinedDiscrTree α) (e : Expr) (unify : Bool) - (config : WhnfCoreConfig) (allowRootStar : Bool := false) : MetaM (Array (Array α × Nat)) := do - let e ← mkDTExpr e config - let result := GetUnify.getMatchWithScoreAux d e unify config allowRootStar + (allowRootStar : Bool := false) : MetaM (Array (Array α × Nat)) := do + let e ← mkDTExpr e + let result := GetUnify.getMatchWithScoreAux d e unify allowRootStar return result.qsort (·.2 > ·.2) /-- Similar to `getMatchWithScore`, but also returns matches with prefixes of `e`. We store the score, followed by the number of ignored arguments. -/ partial def getMatchWithScoreWithExtra (d : RefinedDiscrTree α) (e : Expr) (unify : Bool) - (config : WhnfCoreConfig) (allowRootStar : Bool := false) : + (allowRootStar : Bool := false) : MetaM (Array (Array α × Nat × Nat)) := do let result ← go e 0 return result.qsort (·.2.1 > ·.2.1) where /-- go -/ go (e : Expr) (numIgnored : Nat) : MetaM (Array (Array α × Nat × Nat)) := do - let result ← getMatchWithScore d e unify config allowRootStar + let result ← getMatchWithScore d e unify allowRootStar let result := result.map fun (a, b) => (a, b, numIgnored) match e with | .app e _ => return (← go e (numIgnored + 1)) ++ result diff --git a/Mathlib/Tactic/FunProp/Theorems.lean b/Mathlib/Tactic/FunProp/Theorems.lean index b0c184aedc988..464ce021ba426 100644 --- a/Mathlib/Tactic/FunProp/Theorems.lean +++ b/Mathlib/Tactic/FunProp/Theorems.lean @@ -226,16 +226,16 @@ structure GeneralTheorem where def GeneralTheorem.getProof (thm : GeneralTheorem) : MetaM Expr := do mkConstWithFreshMVarLevels thm.thmName -/-- -/ +/-- Structure holding transition or morphism theorems for `fun_prop` tactic. -/ structure GeneralTheorems where - /-- -/ + /-- Discrimination tree indexing theorems. -/ theorems : RefinedDiscrTree GeneralTheorem := {} deriving Inhabited -/-- -/ +/-- Extendions for transition or morphism theorems -/ abbrev GeneralTheoremsExt := SimpleScopedEnvExtension GeneralTheorem GeneralTheorems -/-- -/ +/-- Environment extension for transition theorems. -/ initialize transitionTheoremsExt : GeneralTheoremsExt ← registerSimpleScopedEnvExtension { name := by exact decl_name% @@ -244,7 +244,18 @@ initialize transitionTheoremsExt : GeneralTheoremsExt ← {d with theorems := e.keys.foldl (RefinedDiscrTree.insertDTExpr · · e) d.theorems} } -/-- -/ +/-- Get transition theorems applicable to `e`. + +For example calling on `e` equal to `Continuous f` might return theorems implying continuity +from linearity over finite dimensional spaces or differentiability. -/ +def getTransitionTheorems (e : Expr) : FunPropM (Array GeneralTheorem) := do + let ext := transitionTheoremsExt.getState (← getEnv) + let candidates ← withConfig (fun cfg => { cfg with iota := false, zeta := false }) <| + ext.theorems.getMatchWithScore e false + let candidates := candidates.map (·.1) |>.flatten + return candidates + +/-- Environment extension for morphism theorems. -/ initialize morTheoremsExt : GeneralTheoremsExt ← registerSimpleScopedEnvExtension { name := by exact decl_name% @@ -254,6 +265,17 @@ initialize morTheoremsExt : GeneralTheoremsExt ← } +/-- Get morphism theorems applicable to `e`. + +For example calling on `e` equal to `Continuous f` for `f : X→L[ℝ] Y` would return theorem +infering continuity from the bundled morphism. -/ +def getMorphismTheorems (e : Expr) : FunPropM (Array GeneralTheorem) := do + let ext := morTheoremsExt.getState (← getEnv) + let candidates ← withConfig (fun cfg => { cfg with iota := false, zeta := false }) <| + ext.theorems.getMatchWithScore e false + let candidates := candidates.map (·.1) |>.flatten + return candidates + -------------------------------------------------------------------------------- @@ -301,13 +323,11 @@ type of theorem it is. -/ def getTheoremFromConst (declName : Name) (prio : Nat := eval_prio default) : MetaM Theorem := do let info ← getConstInfo declName forallTelescope info.type fun xs b => do - let .some (decl,f) ← getFunProp? b | throwError "unrecognized function property `{← ppExpr b}`" let funPropName := decl.funPropName - - let fData? ← getFunctionData? f defaultUnfoldPred {zeta := false} - + let fData? ← + withConfig (fun cfg => { cfg with zeta := false}) <| getFunctionData? f defaultUnfoldPred if let .some thmArgs ← detectLambdaTheoremArgs (← fData?.get) xs then return .lam { funPropName := funPropName @@ -338,7 +358,7 @@ def getTheoremFromConst (declName : Name) (prio : Nat := eval_prio default) : Me } | .fvar .. => let (_,_,b') ← forallMetaTelescope info.type - let keys := ← RefinedDiscrTree.mkDTExprs b' {} false + let keys := ← RefinedDiscrTree.mkDTExprs b' false let thm : GeneralTheorem := { funPropName := funPropName thmName := declName diff --git a/Mathlib/Tactic/FunProp/ToBatteries.lean b/Mathlib/Tactic/FunProp/ToBatteries.lean index f3affc6579c3d..f11a592a4c1ad 100644 --- a/Mathlib/Tactic/FunProp/ToBatteries.lean +++ b/Mathlib/Tactic/FunProp/ToBatteries.lean @@ -35,7 +35,7 @@ def isOrderedSubsetOf {α} [Inhabited α] [DecidableEq α] (a b : Array α) : Bo private def letTelescopeImpl {α} (e : Expr) (k : Array Expr → Expr → MetaM α) : MetaM α := lambdaLetTelescope e fun xs b ↦ do - if let .some i ← xs.findIdxM? (fun x ↦ do pure ¬(← x.fvarId!.isLetVar)) then + if let .some i ← xs.findIdxM? (fun x ↦ do pure !(← x.fvarId!.isLetVar)) then k xs[0:i] (← mkLambdaFVars xs[i:] b) else k xs b diff --git a/Mathlib/Tactic/Linarith/Frontend.lean b/Mathlib/Tactic/Linarith/Frontend.lean index 04b1e07d1ac97..a63112c459aff 100644 --- a/Mathlib/Tactic/Linarith/Frontend.lean +++ b/Mathlib/Tactic/Linarith/Frontend.lean @@ -277,7 +277,7 @@ def runLinarith (cfg : LinarithConfig) (prefType : Option Expr) (g : MVarId) if let some t := prefType then let (i, vs) ← hyp_set.find t proveFalseByLinarith cfg.transparency cfg.oracle cfg.discharger g vs <|> - findLinarithContradiction cfg g ((hyp_set.eraseIdx i).toList.map (·.2)) + findLinarithContradiction cfg g ((hyp_set.eraseIdxIfInBounds i).toList.map (·.2)) else findLinarithContradiction cfg g (hyp_set.toList.map (·.2)) let mut preprocessors := cfg.preprocessors if cfg.splitNe then diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean index 8a5a9488ae1a9..2f6eb09ce7de1 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/Datatypes.lean @@ -69,7 +69,7 @@ instance : UsableInSimplexAlgorithm DenseMatrix where for ⟨i, j, v⟩ in vals do data := data.modify i fun row => row.set! j v return ⟨data⟩ - swapRows mat i j := ⟨mat.data.swap! i j⟩ + swapRows mat i j := ⟨mat.data.swapIfInBounds i j⟩ subtractRow mat i j coef := let newData : Array (Array Rat) := mat.data.modify j fun row => row.zipWith mat.data[i]! fun x y => x - coef * y @@ -101,7 +101,7 @@ instance : UsableInSimplexAlgorithm SparseMatrix where if v != 0 then data := data.modify i fun row => row.insert j v return ⟨data⟩ - swapRows mat i j := ⟨mat.data.swap! i j⟩ + swapRows mat i j := ⟨mat.data.swapIfInBounds i j⟩ subtractRow mat i j coef := let newData := mat.data.modify j fun row => mat.data[i]!.fold (fun cur k val => diff --git a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean index 9858e94c23f14..4ecfb36c3cab1 100644 --- a/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean +++ b/Mathlib/Tactic/Linarith/Oracle/SimplexAlgorithm/SimplexAlgorithm.lean @@ -48,8 +48,8 @@ def doPivotOperation (exitIdx enterIdx : Nat) : SimplexAlgorithmM matType Unit : let newBasic := s.basic.set! exitIdx s.free[enterIdx]! let newFree := s.free.set! enterIdx s.basic[exitIdx]! - have hb : newBasic.size = s.basic.size := by apply Array.size_setD - have hf : newFree.size = s.free.size := by apply Array.size_setD + have hb : newBasic.size = s.basic.size := by apply Array.size_setIfInBounds + have hf : newFree.size = s.free.size := by apply Array.size_setIfInBounds return (⟨newBasic, newFree, hb ▸ hf ▸ mat⟩ : Tableau matType) @@ -60,7 +60,7 @@ nonnegative. def checkSuccess : SimplexAlgorithmM matType Bool := do let lastIdx := (← get).free.size - 1 return (← get).mat[(0, lastIdx)]! > 0 && - (← Nat.allM (← get).basic.size (fun i => do return (← get).mat[(i, lastIdx)]! >= 0)) + (← (← get).basic.size.allM (fun i _ => do return (← get).mat[(i, lastIdx)]! ≥ 0)) /-- Chooses an entering variable: among the variables with a positive coefficient in the objective diff --git a/Mathlib/Tactic/Linarith/Preprocessing.lean b/Mathlib/Tactic/Linarith/Preprocessing.lean index eda221c8c33d1..f714751349976 100644 --- a/Mathlib/Tactic/Linarith/Preprocessing.lean +++ b/Mathlib/Tactic/Linarith/Preprocessing.lean @@ -30,7 +30,7 @@ namespace Linarith /-! ### Preprocessing -/ -open Lean hiding Rat +open Lean open Elab Tactic Meta open Qq open Mathlib @@ -287,6 +287,50 @@ partial def findSquares (s : RBSet (Nat × Bool) lexOrd.compare) (e : Expr) : e.foldlM findSquares s | _ => e.foldlM findSquares s +/-- Get proofs of `-x^2 ≤ 0` and `-(x*x) ≤ 0`, when those terms appear in `ls` -/ +private def nlinarithGetSquareProofs (ls : List Expr) : MetaM (List Expr) := do + -- find the squares in `AtomM` to ensure deterministic behavior + let s ← AtomM.run .reducible do + let si ← ls.foldrM (fun h s' => do findSquares s' (← instantiateMVars (← inferType h))) + RBSet.empty + si.toList.mapM fun (i, is_sq) => return ((← get).atoms[i]!, is_sq) + let new_es ← s.filterMapM fun (e, is_sq) => + observing? <| mkAppM (if is_sq then ``sq_nonneg else ``mul_self_nonneg) #[e] + let new_es ← compWithZero.globalize.transform new_es + trace[linarith] "nlinarith preprocessing found squares" + trace[linarith] "{s}" + linarithTraceProofs "so we added proofs" new_es + return new_es + +/-- +Get proofs for products of inequalities from `ls`. + +Note that the length of the resulting list is proportional to `ls.length^2`, which can make a large +amount of work for the linarith oracle. +-/ +private def nlinarithGetProductsProofs (ls : List Expr) : MetaM (List Expr) := do + let with_comps ← ls.mapM (fun e => do + let tp ← inferType e + try + let ⟨ine, _⟩ ← parseCompAndExpr tp + pure (ine, e) + catch _ => pure (Ineq.lt, e)) + 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] + | _, Ineq.eq => mkAppM ``mul_zero_eq #[a, b] + | Ineq.lt, Ineq.lt => mkAppM ``mul_pos_of_neg_of_neg #[a, b] + | Ineq.lt, Ineq.le => do + let a ← mkAppM ``le_of_lt #[a] + mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b] + | Ineq.le, Ineq.lt => do + let b ← mkAppM ``le_of_lt #[b] + mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b] + | Ineq.le, Ineq.le => mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b]) + catch _ => pure none + compWithZero.globalize.transform products.reduceOption + /-- `nlinarithExtras` is the preprocessor corresponding to the `nlinarith` tactic. @@ -299,38 +343,8 @@ This preprocessor is typically run last, after all inputs have been canonized. def nlinarithExtras : GlobalPreprocessor where name := "nonlinear arithmetic extras" transform ls := do - -- find the squares in `AtomM` to ensure deterministic behavior - let s ← AtomM.run .reducible do - let si ← ls.foldrM (fun h s' => do findSquares s' (← instantiateMVars (← inferType h))) - RBSet.empty - si.toList.mapM fun (i, is_sq) => return ((← get).atoms[i]!, is_sq) - let new_es ← s.filterMapM fun (e, is_sq) => - observing? <| mkAppM (if is_sq then ``sq_nonneg else ``mul_self_nonneg) #[e] - let new_es ← compWithZero.globalize.transform new_es - trace[linarith] "nlinarith preprocessing found squares" - trace[linarith] "{s}" - linarithTraceProofs "so we added proofs" new_es - let with_comps ← (new_es ++ ls).mapM (fun e => do - let tp ← inferType e - try - let ⟨ine, _⟩ ← parseCompAndExpr tp - pure (ine, e) - catch _ => pure (Ineq.lt, e)) - 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] - | _, Ineq.eq => mkAppM ``mul_zero_eq #[a, b] - | Ineq.lt, Ineq.lt => mkAppM ``mul_pos_of_neg_of_neg #[a, b] - | Ineq.lt, Ineq.le => do - let a ← mkAppM ``le_of_lt #[a] - mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b] - | Ineq.le, Ineq.lt => do - let b ← mkAppM ``le_of_lt #[b] - mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b] - | Ineq.le, Ineq.le => mkAppM ``mul_nonneg_of_nonpos_of_nonpos #[a, b]) - catch _ => pure none - let products ← compWithZero.globalize.transform products.reduceOption + let new_es ← nlinarithGetSquareProofs ls + let products ← nlinarithGetProductsProofs (new_es ++ ls) return (new_es ++ ls ++ products) end nlinarith diff --git a/Mathlib/Tactic/LinearCombination'.lean b/Mathlib/Tactic/LinearCombination'.lean index c7965a7998ee9..d322231af38f8 100644 --- a/Mathlib/Tactic/LinearCombination'.lean +++ b/Mathlib/Tactic/LinearCombination'.lean @@ -36,7 +36,7 @@ implementation, but this version is provided for backward-compatibility. -/ namespace Mathlib.Tactic.LinearCombination' -open Lean hiding Rat +open Lean open Elab Meta Term variable {α : Type*} {a a' a₁ a₂ b b' b₁ b₂ c : α} diff --git a/Mathlib/Tactic/LinearCombination.lean b/Mathlib/Tactic/LinearCombination.lean index d5f5a2b863b2e..88ba7708252df 100644 --- a/Mathlib/Tactic/LinearCombination.lean +++ b/Mathlib/Tactic/LinearCombination.lean @@ -36,7 +36,7 @@ Lastly, calls a normalization tactic on this target. -/ namespace Mathlib.Tactic.LinearCombination -open Lean hiding Rat +open Lean open Elab Meta Term Mathlib Ineq /-- Result of `expandLinearCombo`, either an equality/inequality proof or a value. -/ diff --git a/Mathlib/Tactic/Linter/FlexibleLinter.lean b/Mathlib/Tactic/Linter/FlexibleLinter.lean index fbb790088e980..f4ad7305528d7 100644 --- a/Mathlib/Tactic/Linter/FlexibleLinter.lean +++ b/Mathlib/Tactic/Linter/FlexibleLinter.lean @@ -343,8 +343,7 @@ Otherwise, if an `FVarId` with the same `userName` exists in the new context, us If both of these fail, return `default` (i.e. "fail"). -/ def persistFVars (fv : FVarId) (before after : LocalContext) : FVarId := let ldecl := (before.find? fv).getD default - let name := ldecl.userName - (getFVarIdCandidates fv name after).getD 0 default + (getFVarIdCandidates fv ldecl.userName after).getD 0 default /-- `reallyPersist` converts an array of pairs `(fvar, mvar)` to another array of the same type. -/ def reallyPersist @@ -376,11 +375,11 @@ def flexibleLinter : Linter where run := withSetOptionIn fun _stx => do if (← MonadState.get).messages.hasErrors then return let trees ← getInfoTrees - let x := trees.toList.map (extractCtxAndGoals (fun _ => true)) + let x := trees.map (extractCtxAndGoals (fun _ => true)) -- `stains` records pairs `(location, mvar)`, where -- * `location` is either a hypothesis or the main goal modified by a flexible tactic and -- * `mvar` is the metavariable containing the modified location - let mut stains : Array ((FVarId × MVarId) × (Stained × Syntax)) := .empty + let mut stains : Array ((FVarId × MVarId) × (Stained × Syntax)) := #[] let mut msgs : Array (Syntax × Syntax × Stained) := #[] for d in x do for (s, ctx0, ctx1, mvs0, mvs1) in d do let skind := s.getKind @@ -389,17 +388,14 @@ def flexibleLinter : Linter where run := withSetOptionIn fun _stx => do for d in getStained! s do if shouldStain? then for currMVar1 in mvs1 do - let lctx1 := ((ctx1.decls.find? currMVar1).getD default).lctx + let lctx1 := (ctx1.decls.findD currMVar1 default).lctx let locsAfter := d.toFMVarId currMVar1 lctx1 - - for l in locsAfter do - stains := stains.push (l, (d, s)) - + stains := stains ++ locsAfter.map (fun l ↦ (l, (d, s))) else let stained_in_syntax := if usesGoal? skind then (toStained s).insert d else toStained s if !flexible.contains skind then for currMv0 in mvs0 do - let lctx0 := ((ctx0.decls.find? currMv0).getD default).lctx + let lctx0 := (ctx0.decls.findD currMv0 default).lctx let mut foundFvs : Std.HashSet (FVarId × MVarId):= {} for st in stained_in_syntax do for d in st.toFMVarId currMv0 lctx0 do diff --git a/Mathlib/Tactic/Linter/HaveLetLinter.lean b/Mathlib/Tactic/Linter/HaveLetLinter.lean index fe586741660b6..b88a5344a4265 100644 --- a/Mathlib/Tactic/Linter/HaveLetLinter.lean +++ b/Mathlib/Tactic/Linter/HaveLetLinter.lean @@ -66,21 +66,21 @@ def InfoTree.foldInfoM {α m} [Monad m] (f : ContextInfo → Info → α → m InfoTree → m α := InfoTree.foldInfo (fun ctx i ma => do f ctx i (← ma)) (pure init) -/-- given a `ContextInfo`, a `LocalContext` and an `Array` of `Expr`essions `es`, -`areProp_toFormat` creates a `MetaM` context, and returns an array of pairs consisting of -* a `Bool`ean, answering the question of whether the Type of `e` is a `Prop` or not, and -* the pretty-printed `Format` of `e` -for each `Expr`ession `e` in `es`. -Concretely, `areProp_toFormat` runs `inferType` in `CommandElabM`. +/-- given a `ContextInfo`, a `LocalContext` and an `Array` of `Expr`essions `es` with a `Name`, +`toFormat_propTypes` creates a `MetaM` context, and returns an array of +the pretty-printed `Format` of `e`, together with the (unchanged) name +for each `Expr`ession `e` in `es` whose type is a `Prop`. + +Concretely, `toFormat_propTypes` runs `inferType` in `CommandElabM`. This is the kind of monadic lift that `nonPropHaves` uses to decide whether the Type of a `have` is in `Prop` or not. The output `Format` is just so that the linter displays a better message. -/ -def areProp_toFormat (ctx : ContextInfo) (lc : LocalContext) (es : Array Expr) : - CommandElabM (Array (Bool × Format)) := do +def toFormat_propTypes (ctx : ContextInfo) (lc : LocalContext) (es : Array (Expr × Name)) : + CommandElabM (Array (Format × Name)) := do ctx.runMetaM lc do - es.mapM fun e => do + es.filterMapM fun (e, name) ↦ do let typ ← inferType (← instantiateMVars e) - return (typ.isProp, ← ppExpr e) + if typ.isProp then return none else return (← ppExpr e, name) /-- returns the `have` syntax whose corresponding hypothesis does not have Type `Prop` and also a `Format`ted version of the corresponding Type. -/ @@ -92,26 +92,22 @@ def nonPropHaves : InfoTree → CommandElabM (Array (Syntax × Format)) := let .original .. := stx.getHeadInfo | return #[] unless isHave? stx do return #[] let mctx := i.mctxAfter - let mvdecls := (i.goalsAfter.map (mctx.decls.find? ·)).reduceOption - -- we extract the `MetavarDecl` with largest index after a `have`, since this one - -- holds information about the metavariable where `have` introduces the new hypothesis. - let largestIdx := mvdecls.toArray.qsort (·.index > ·.index) - -- the relevant `LocalContext` - let lc := (largestIdx.getD 0 default).lctx + let mvdecls := i.goalsAfter.filterMap (mctx.decls.find? ·) + -- We extract the `MetavarDecl` with largest index after a `have`, since this one + -- holds information about the metavariable where `have` introduces the new hypothesis, + -- and determine the relevant `LocalContext`. + let lc := mvdecls.toArray.getMax? (·.index < ·.index) |>.getD default |>.lctx -- we also accumulate all `fvarId`s from all local contexts before the use of `have` -- so that we can then isolate the `fvarId`s that are created by `have` - let oldMvdecls := (i.goalsBefore.map (mctx.decls.find? ·)).reduceOption - let oldLctx := oldMvdecls.map (·.lctx) - let oldDecls := (oldLctx.map (·.decls.toList.reduceOption)).flatten - let oldFVars := oldDecls.map (·.fvarId) - -- `newDecls` are the local declarations whose `FVarID` did not exist before the `have` - -- effectively they are the declarations that we want to test for being in `Prop` or not. + let oldMvdecls := i.goalsBefore.filterMap (mctx.decls.find? ·) + let oldFVars := (oldMvdecls.map (·.lctx.decls.toList.reduceOption)).flatten.map (·.fvarId) + -- `newDecls` are the local declarations whose `FVarID` did not exist before the `have`. + -- Effectively they are the declarations that we want to test for being in `Prop` or not. let newDecls := lc.decls.toList.reduceOption.filter (! oldFVars.contains ·.fvarId) - -- now, we get the `MetaM` state up and running to find the types of each entry of `newDecls` - let fmts ← areProp_toFormat ctx lc (newDecls.map (·.type)).toArray - let (_propFmts, typeFmts) := (fmts.zip (newDecls.map (·.userName)).toArray).partition (·.1.1) - -- everything that is a Type triggers a warning on `have` - return typeFmts.map fun ((_, fmt), na) => (stx, f!"{na} : {fmt}")) + -- Now, we get the `MetaM` state up and running to find the types of each entry of `newDecls`. + -- For each entry which is a `Type`, we print a warning on `have`. + let fmts ← toFormat_propTypes ctx lc (newDecls.map (fun e ↦ (e.type, e.userName))).toArray + return fmts.map fun (fmt, na) ↦ (stx, f!"{na} : {fmt}")) /-- The main implementation of the `have` vs `let` linter. -/ def haveLetLinter : Linter where run := withSetOptionIn fun _stx => do @@ -120,7 +116,7 @@ def haveLetLinter : Linter where run := withSetOptionIn fun _stx => do return unless gh == 1 && (← MonadState.get).messages.unreported.isEmpty do let trees ← getInfoTrees - for t in trees.toArray do + for t in trees do for (s, fmt) in ← nonPropHaves t do -- Since the linter option is not in `Bool`, the standard `Linter.logLint` does not work. -- We emulate it with `logWarningAt` diff --git a/Mathlib/Tactic/Linter/Multigoal.lean b/Mathlib/Tactic/Linter/Multigoal.lean index e1d838948d7f9..cd119e103387b 100644 --- a/Mathlib/Tactic/Linter/Multigoal.lean +++ b/Mathlib/Tactic/Linter/Multigoal.lean @@ -61,7 +61,7 @@ There is some overlap in scope between `ignoreBranch` and `exclusions`. Tactic combinators like `repeat` or `try` are a mix of both. -/ -abbrev exclusions : Std.HashSet SyntaxNodeKind := .ofList [ +abbrev exclusions : Std.HashSet SyntaxNodeKind := .ofArray #[ -- structuring a proof ``Lean.Parser.Term.cdot, ``cdot, @@ -112,7 +112,7 @@ Reasons for ignoring these tactics include There is some overlap in scope between `exclusions` and `ignoreBranch`. -/ -abbrev ignoreBranch : Std.HashSet SyntaxNodeKind := .ofList [ +abbrev ignoreBranch : Std.HashSet SyntaxNodeKind := .ofArray #[ ``Lean.Parser.Tactic.Conv.conv, `Mathlib.Tactic.Conv.convLHS, `Mathlib.Tactic.Conv.convRHS, @@ -161,7 +161,7 @@ def multiGoalLinter : Linter where run := withSetOptionIn fun _stx ↦ do if (← get).messages.hasErrors then return let trees ← getInfoTrees - for t in trees.toArray do + for t in trees do for (s, before, after, n) in getManyGoals t do let goals (k : Nat) := if k == 1 then f!"1 goal" else f!"{k} goals" let fmt ← Command.liftCoreM diff --git a/Mathlib/Tactic/Linter/OldObtain.lean b/Mathlib/Tactic/Linter/OldObtain.lean index 34997e37d0fc6..f9d77e63e79e8 100644 --- a/Mathlib/Tactic/Linter/OldObtain.lean +++ b/Mathlib/Tactic/Linter/OldObtain.lean @@ -54,12 +54,15 @@ open Lean Elab namespace Mathlib.Linter.Style /-- Whether a syntax element is an `obtain` tactic call without a provided proof. -/ -def is_obtain_without_proof : Syntax → Bool +def isObtainWithoutProof : Syntax → Bool -- Using the `obtain` tactic without a proof requires proving a type; -- a pattern is optional. | `(tactic|obtain : $_type) | `(tactic|obtain $_pat : $_type) => true | _ => false +/-- Deprecated alias for `Mathlib.Linter.Style.isObtainWithoutProof`. -/ +@[deprecated isObtainWithoutProof (since := "2024-12-07")] +def is_obtain_without_proof := @isObtainWithoutProof /-- The `oldObtain` linter emits a warning upon uses of the "stream-of-conciousness" variants of the `obtain` tactic, i.e. with the proof postponed. -/ @@ -74,7 +77,7 @@ def oldObtainLinter : Linter where run := withSetOptionIn fun stx => do return if (← MonadState.get).messages.hasErrors then return - if let some head := stx.find? is_obtain_without_proof then + if let some head := stx.find? isObtainWithoutProof then Linter.logLint linter.oldObtain head m!"Please remove stream-of-conciousness `obtain` syntax" initialize addLinter oldObtainLinter diff --git a/Mathlib/Tactic/Linter/PPRoundtrip.lean b/Mathlib/Tactic/Linter/PPRoundtrip.lean index 9f8e258ecd46f..df238e0927ee3 100644 --- a/Mathlib/Tactic/Linter/PPRoundtrip.lean +++ b/Mathlib/Tactic/Linter/PPRoundtrip.lean @@ -60,7 +60,7 @@ def polishSource (s : String) : String × Array Nat := let preWS := split.foldl (init := #[]) fun p q => let txt := q.trimLeft.length (p.push (q.length - txt)).push txt - let preWS := preWS.eraseIdx 0 + let preWS := preWS.eraseIdxIfInBounds 0 let s := (split.map .trimLeft).filter (· != "") (" ".intercalate (s.filter (!·.isEmpty)), preWS) diff --git a/Mathlib/Tactic/Linter/Style.lean b/Mathlib/Tactic/Linter/Style.lean index 65272ba2d6d0a..bbe2f16f58a98 100644 --- a/Mathlib/Tactic/Linter/Style.lean +++ b/Mathlib/Tactic/Linter/Style.lean @@ -52,16 +52,24 @@ namespace Style.setOption /-- Whether a syntax element is a `set_option` command, tactic or term: Return the name of the option being set, if any. -/ -def parse_set_option : Syntax → Option Name +def parseSetOption : Syntax → Option Name -- This handles all four possibilities of `_val`: a string, number, `true` and `false`. | `(command|set_option $name:ident $_val) => some name.getId | `(set_option $name:ident $_val in $_x) => some name.getId | `(tactic|set_option $name:ident $_val in $_x) => some name.getId | _ => none +/-- Deprecated alias for `Mathlib.Linter.Style.setOption.parseSetOption`. -/ +@[deprecated parseSetOption (since := "2024-12-07")] +def parse_set_option := @parseSetOption + /-- Whether a given piece of syntax is a `set_option` command, tactic or term. -/ -def is_set_option : Syntax → Bool := - fun stx ↦ parse_set_option stx matches some _name +def isSetOption : Syntax → Bool := + fun stx ↦ parseSetOption stx matches some _name + +/-- Deprecated alias for `Mathlib.Linter.Style.setOption.isSetOption`. -/ +@[deprecated isSetOption (since := "2024-12-07")] +def is_set_option := @isSetOption /-- The `setOption` linter: this lints any `set_option` command, term or tactic which sets a `pp`, `profiler` or `trace` option. @@ -76,8 +84,8 @@ def setOptionLinter : Linter where run := withSetOptionIn fun stx => do return if (← MonadState.get).messages.hasErrors then return - if let some head := stx.find? is_set_option then - if let some name := parse_set_option head then + if let some head := stx.find? isSetOption then + if let some name := parseSetOption head then let forbidden := [`debug, `pp, `profiler, `trace] if forbidden.contains name.getRoot then Linter.logLint linter.style.setOption head diff --git a/Mathlib/Tactic/Linter/UnusedTactic.lean b/Mathlib/Tactic/Linter/UnusedTactic.lean index 81dea423b38b4..01c6ba0915ce9 100644 --- a/Mathlib/Tactic/Linter/UnusedTactic.lean +++ b/Mathlib/Tactic/Linter/UnusedTactic.lean @@ -72,32 +72,33 @@ abbrev M := StateRefT (Std.HashMap String.Range Syntax) IO This can be increased dynamically, using `#allow_unused_tactic`. -/ initialize allowedRef : IO.Ref (Std.HashSet SyntaxNodeKind) ← - IO.mkRef <| Std.HashSet.empty - |>.insert `Mathlib.Tactic.Says.says - |>.insert `Batteries.Tactic.«tacticOn_goal-_=>_» + IO.mkRef <| .ofArray #[ + `Mathlib.Tactic.Says.says, + `Batteries.Tactic.«tacticOn_goal-_=>_», -- attempt to speed up, by ignoring more tactics - |>.insert `by - |>.insert `null - |>.insert `«]» - |>.insert ``Lean.Parser.Term.byTactic - |>.insert ``Lean.Parser.Tactic.tacticSeq - |>.insert ``Lean.Parser.Tactic.tacticSeq1Indented - |>.insert ``Lean.Parser.Tactic.tacticTry_ + `by, + `null, + `«]», + ``Lean.Parser.Term.byTactic, + ``Lean.Parser.Tactic.tacticSeq, + ``Lean.Parser.Tactic.tacticSeq1Indented, + ``Lean.Parser.Tactic.tacticTry_, -- the following `SyntaxNodeKind`s play a role in silencing `test`s - |>.insert ``Lean.Parser.Tactic.guardHyp - |>.insert ``Lean.Parser.Tactic.guardTarget - |>.insert ``Lean.Parser.Tactic.failIfSuccess - |>.insert `Mathlib.Tactic.successIfFailWithMsg - |>.insert `Mathlib.Tactic.failIfNoProgress - |>.insert `Mathlib.Tactic.ExtractGoal.extractGoal - |>.insert `Mathlib.Tactic.Propose.propose' - |>.insert `Lean.Parser.Tactic.traceState - |>.insert `Mathlib.Tactic.tacticMatch_target_ - |>.insert ``Lean.Parser.Tactic.change - |>.insert `change? - |>.insert `«tactic#adaptation_note_» - |>.insert `tacticSleep_heartbeats_ - |>.insert `Mathlib.Tactic.«tacticRename_bvar_→__» + ``Lean.Parser.Tactic.guardHyp, + ``Lean.Parser.Tactic.guardTarget, + ``Lean.Parser.Tactic.failIfSuccess, + `Mathlib.Tactic.successIfFailWithMsg, + `Mathlib.Tactic.failIfNoProgress, + `Mathlib.Tactic.ExtractGoal.extractGoal, + `Mathlib.Tactic.Propose.propose', + `Lean.Parser.Tactic.traceState, + `Mathlib.Tactic.tacticMatch_target_, + ``Lean.Parser.Tactic.change, + `change?, + `«tactic#adaptation_note_», + `tacticSleep_heartbeats_, + `Mathlib.Tactic.«tacticRename_bvar_→__» + ] /-- `#allow_unused_tactic` takes an input a space-separated list of identifiers. These identifiers are then allowed by the unused tactic linter: @@ -119,35 +120,35 @@ A list of blacklisted syntax kinds, which are expected to have subterms that con unevaluated tactics. -/ initialize ignoreTacticKindsRef : IO.Ref NameHashSet ← - IO.mkRef <| Std.HashSet.empty - |>.insert `Mathlib.Tactic.Says.says - |>.insert ``Parser.Term.binderTactic - |>.insert ``Lean.Parser.Term.dynamicQuot - |>.insert ``Lean.Parser.Tactic.quotSeq - |>.insert ``Lean.Parser.Tactic.tacticStop_ - |>.insert ``Lean.Parser.Command.notation - |>.insert ``Lean.Parser.Command.mixfix - |>.insert ``Lean.Parser.Tactic.discharger - |>.insert ``Lean.Parser.Tactic.Conv.conv - |>.insert `Batteries.Tactic.seq_focus - |>.insert `Mathlib.Tactic.Hint.registerHintStx - |>.insert `Mathlib.Tactic.LinearCombination.linearCombination - |>.insert `Mathlib.Tactic.LinearCombination'.linearCombination' - |>.insert `Aesop.Frontend.Parser.addRules - |>.insert `Aesop.Frontend.Parser.aesopTactic - |>.insert `Aesop.Frontend.Parser.aesopTactic? + IO.mkRef <| .ofArray #[ + `Mathlib.Tactic.Says.says, + ``Parser.Term.binderTactic, + ``Lean.Parser.Term.dynamicQuot, + ``Lean.Parser.Tactic.quotSeq, + ``Lean.Parser.Tactic.tacticStop_, + ``Lean.Parser.Command.notation, + ``Lean.Parser.Command.mixfix, + ``Lean.Parser.Tactic.discharger, + ``Lean.Parser.Tactic.Conv.conv, + `Batteries.Tactic.seq_focus, + `Mathlib.Tactic.Hint.registerHintStx, + `Mathlib.Tactic.LinearCombination.linearCombination, + `Mathlib.Tactic.LinearCombination'.linearCombination', + `Aesop.Frontend.Parser.addRules, + `Aesop.Frontend.Parser.aesopTactic, + `Aesop.Frontend.Parser.aesopTactic?, -- the following `SyntaxNodeKind`s play a role in silencing `test`s - |>.insert ``Lean.Parser.Tactic.failIfSuccess - |>.insert `Mathlib.Tactic.successIfFailWithMsg - |>.insert `Mathlib.Tactic.failIfNoProgress + ``Lean.Parser.Tactic.failIfSuccess, + `Mathlib.Tactic.successIfFailWithMsg, + `Mathlib.Tactic.failIfNoProgress + ] /-- Is this a syntax kind that contains intentionally unused tactic subterms? -/ def isIgnoreTacticKind (ignoreTacticKinds : NameHashSet) (k : SyntaxNodeKind) : Bool := k.components.contains `Conv || "slice".isPrefixOf k.toString || - match k with - | .str _ "quot" => true - | _ => ignoreTacticKinds.contains k + k matches .str _ "quot" || + ignoreTacticKinds.contains k /-- Adds a new syntax kind whose children will be ignored by the `unusedTactic` linter. diff --git a/Mathlib/Tactic/MinImports.lean b/Mathlib/Tactic/MinImports.lean index 05f758440185c..c9544b2b3bae9 100644 --- a/Mathlib/Tactic/MinImports.lean +++ b/Mathlib/Tactic/MinImports.lean @@ -215,10 +215,10 @@ def minImpsCore (stx id : Syntax) : CommandElabM Unit := do /-- `#min_imports in cmd` scans the syntax `cmd` and the declaration obtained by elaborating `cmd` to find a collection of minimal imports that should be sufficient for `cmd` to work. -/ -syntax (name := minImpsStx) "#min_imports in" command : command +syntax (name := minImpsStx) "#min_imports" "in" command : command @[inherit_doc minImpsStx] -syntax "#min_imports in" term : command +syntax "#min_imports" "in" term : command elab_rules : command | `(#min_imports in $cmd:command) => do diff --git a/Mathlib/Tactic/Module.lean b/Mathlib/Tactic/Module.lean index e06d5ce2088c2..14274913e2c77 100644 --- a/Mathlib/Tactic/Module.lean +++ b/Mathlib/Tactic/Module.lean @@ -573,10 +573,7 @@ def postprocess (mvarId : MVarId) : MetaM MVarId := do let ⟨levelParams, _, proof⟩ ← abstractMVars (mkConst thm) thms ← thms.add (.stx (← mkFreshId) Syntax.missing) levelParams proof -- now run `simp` with these lemmas, and (importantly) *no* simprocs - let ctx : Simp.Context := { - config := { failIfUnchanged := false } - simpTheorems := #[thms] - } + let ctx ← Simp.mkContext { failIfUnchanged := false } (simpTheorems := #[thms]) let (some r, _) ← simpTarget mvarId ctx (simprocs := #[]) | throwError "internal error in match_scalars tactic: postprocessing should not close goals" return r diff --git a/Mathlib/Tactic/MoveAdd.lean b/Mathlib/Tactic/MoveAdd.lean index 4cee13436d339..76c4709fd49a4 100644 --- a/Mathlib/Tactic/MoveAdd.lean +++ b/Mathlib/Tactic/MoveAdd.lean @@ -195,7 +195,8 @@ def reorderUsing (toReorder : List α) (instructions : List (α × Bool)) : List let uToReorder := (uniquify toReorder).toArray let reorder := uToReorder.qsort fun x y => match uInstructions.find? (Prod.fst · == x), uInstructions.find? (Prod.fst · == y) with - | none, none => (uToReorder.getIdx? x).get! ≤ (uToReorder.getIdx? y).get! + | none, none => + ((uToReorder.indexOf? x).map Fin.val).get! ≤ ((uToReorder.indexOf? y).map Fin.val).get! | _, _ => weight uInstructions x ≤ weight uInstructions y (reorder.map Prod.fst).toList @@ -335,7 +336,7 @@ def pairUp : List (Expr × Bool × Syntax) → List Expr → To support a new binary operation, extend the list in this definition, so that it contains enough lemmas to allow `simp` to close a generic permutation goal for the new binary operation. -/ -def move_oper_simpCtx : MetaM Simp.Context := do +def moveOperSimpCtx : MetaM Simp.Context := do let simpNames := Elab.Tactic.simpOnlyBuiltins ++ [ ``add_comm, ``add_assoc, ``add_left_comm, -- for `HAdd.hAdd` ``mul_comm, ``mul_assoc, ``mul_left_comm, -- for `HMul.hMul` @@ -345,7 +346,10 @@ def move_oper_simpCtx : MetaM Simp.Context := do ``min_comm, ``min_assoc, ``min_left_comm -- for `min` ] let simpThms ← simpNames.foldlM (·.addConst ·) ({} : SimpTheorems) - return { simpTheorems := #[simpThms] } + Simp.mkContext {} (simpTheorems := #[simpThms]) + +@[deprecated (since := "2024-12-07")] +alias move_oper_simpCtx := moveOperSimpCtx /-- `reorderAndSimp mv op instr` takes as input an `MVarId` `mv`, the name `op` of a binary operation and a list of "instructions" `instr` that it passes to `permuteExpr`. @@ -367,7 +371,7 @@ def reorderAndSimp (mv : MVarId) (instr : List (Expr × Bool)) : throwError m!"There should only be 2 goals, instead of {twoGoals.length}" -- `permGoal` is the single goal `mv_permuted`, possibly more operations will be permuted later on let permGoal ← twoGoals.filterM fun v => return !(← v.isAssigned) - match ← (simpGoal (permGoal[1]!) (← move_oper_simpCtx)) with + match ← (simpGoal (permGoal[1]!) (← moveOperSimpCtx)) with | (some x, _) => throwError m!"'move_oper' could not solve {indentD x.2}" | (none, _) => return permGoal diff --git a/Mathlib/Tactic/NormNum/Basic.lean b/Mathlib/Tactic/NormNum/Basic.lean index e5511ceb38673..a1d9e39f9a55b 100644 --- a/Mathlib/Tactic/NormNum/Basic.lean +++ b/Mathlib/Tactic/NormNum/Basic.lean @@ -34,7 +34,7 @@ the unused variable linter can not see usages of variables in set_option linter.unusedVariables false namespace Mathlib -open Lean hiding Rat mkRat +open Lean open Meta namespace Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/BigOperators.lean b/Mathlib/Tactic/NormNum/BigOperators.lean index a5cb43afd77a6..b6851faeaa70e 100644 --- a/Mathlib/Tactic/NormNum/BigOperators.lean +++ b/Mathlib/Tactic/NormNum/BigOperators.lean @@ -38,7 +38,7 @@ In particular, we can't use the plugin on sums containing variables. namespace Mathlib.Meta -open Lean hiding Rat mkRat +open Lean open Meta open Qq diff --git a/Mathlib/Tactic/NormNum/Core.lean b/Mathlib/Tactic/NormNum/Core.lean index 507719e25a60a..65bc7ba6a5a39 100644 --- a/Mathlib/Tactic/NormNum/Core.lean +++ b/Mathlib/Tactic/NormNum/Core.lean @@ -17,7 +17,7 @@ The actual behavior is in `@[norm_num]`-tagged definitions in `Tactic.NormNum.Ba and elsewhere. -/ -open Lean hiding Rat mkRat +open Lean open Lean.Meta Qq Lean.Elab Term /-- Attribute for identifying `norm_num` extensions. -/ @@ -60,9 +60,6 @@ structure NormNums where erased : PHashSet Name := {} deriving Inhabited -/-- Configuration for `DiscrTree`. -/ -def discrTreeConfig : WhnfCoreConfig := {} - /-- Environment extensions for `norm_num` declarations -/ initialize normNumExt : ScopedEnvExtension Entry (Entry × NormNumExt) NormNums ← -- we only need this to deduplicate entries in the DiscrTree @@ -86,7 +83,7 @@ def derive {α : Q(Type u)} (e : Q($α)) (post := false) : MetaM (Result e) := d profileitM Exception "norm_num" (← getOptions) do let s ← saveState let normNums := normNumExt.getState (← getEnv) - let arr ← normNums.tree.getMatch e discrTreeConfig + let arr ← normNums.tree.getMatch e for ext in arr do if (bif post then ext.post else ext.pre) && ! normNums.erased.contains ext.name then try @@ -180,7 +177,7 @@ initialize registerBuiltinAttribute { let e ← elabTerm stx none let (_, _, e) ← lambdaMetaTelescope (← mkLambdaFVars (← getLCtx).getFVars e) return e - DiscrTree.mkPath e discrTreeConfig + DiscrTree.mkPath e normNumExt.add ((keys, declName), ext) kind | _ => throwUnsupportedSyntax erase := fun declName => do @@ -239,7 +236,7 @@ def normNumAt (g : MVarId) (ctx : Simp.Context) (fvarIdsToSimp : Array FVarId) for fvarId in fvarIdsToSimp do let localDecl ← fvarId.getDecl let type ← instantiateMVars localDecl.type - let ctx := { ctx with simpTheorems := ctx.simpTheorems.eraseTheorem (.fvar localDecl.fvarId) } + let ctx := ctx.setSimpTheorems (ctx.simpTheorems.eraseTheorem (.fvar localDecl.fvarId)) let r ← deriveSimp ctx useSimp type match r.proof? with | some _ => @@ -275,13 +272,14 @@ def getSimpContext (cfg args : Syntax) (simpOnly := false) : TacticM Simp.Contex if simpOnly then simpOnlyBuiltins.foldlM (·.addConst ·) {} else getSimpTheorems let mut { ctx, simprocs := _, starArg } ← elabSimpArgs args[0] (eraseLocal := false) (kind := .simp) (simprocs := {}) - { config, simpTheorems := #[simpTheorems], congrTheorems := ← getSimpCongrTheorems } + (← Simp.mkContext config (simpTheorems := #[simpTheorems]) + (congrTheorems := ← getSimpCongrTheorems)) unless starArg do return ctx let mut simpTheorems := ctx.simpTheorems for h in ← getPropHyps do unless simpTheorems.isErased (.fvar h) do simpTheorems ← simpTheorems.addTheorem (.fvar h) (← h.getDecl).toExpr - pure { ctx with simpTheorems } + return ctx.setSimpTheorems simpTheorems open Elab.Tactic in /-- diff --git a/Mathlib/Tactic/NormNum/DivMod.lean b/Mathlib/Tactic/NormNum/DivMod.lean index 17f454c519354..90f6938e16c6b 100644 --- a/Mathlib/Tactic/NormNum/DivMod.lean +++ b/Mathlib/Tactic/NormNum/DivMod.lean @@ -22,7 +22,7 @@ the unused variable linter can not see usages of variables in set_option linter.unusedVariables false namespace Mathlib -open Lean hiding Rat mkRat +open Lean open Meta namespace Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/OfScientific.lean b/Mathlib/Tactic/NormNum/OfScientific.lean index c494615ef34f0..022e8ff81ca0e 100644 --- a/Mathlib/Tactic/NormNum/OfScientific.lean +++ b/Mathlib/Tactic/NormNum/OfScientific.lean @@ -11,7 +11,7 @@ import Mathlib.Data.Rat.Cast.Lemmas -/ namespace Mathlib -open Lean hiding Rat mkRat +open Lean open Meta namespace Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/Pow.lean b/Mathlib/Tactic/NormNum/Pow.lean index 710bb86159091..467a97ad68b3f 100644 --- a/Mathlib/Tactic/NormNum/Pow.lean +++ b/Mathlib/Tactic/NormNum/Pow.lean @@ -19,7 +19,7 @@ the unused variable linter can not see usages of variables in set_option linter.unusedVariables false namespace Mathlib -open Lean hiding Rat mkRat +open Lean open Meta namespace Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/PowMod.lean b/Mathlib/Tactic/NormNum/PowMod.lean index f50964e19a2b3..b3ac0901c7829 100644 --- a/Mathlib/Tactic/NormNum/PowMod.lean +++ b/Mathlib/Tactic/NormNum/PowMod.lean @@ -24,7 +24,7 @@ The approach taken here is identical to (and copied from) the development in `No set_option autoImplicit true namespace Mathlib -open Lean hiding Rat mkRat +open Lean open Meta namespace Meta.NormNum diff --git a/Mathlib/Tactic/NormNum/Result.lean b/Mathlib/Tactic/NormNum/Result.lean index 85a73f0db9eca..aa37896d595c5 100644 --- a/Mathlib/Tactic/NormNum/Result.lean +++ b/Mathlib/Tactic/NormNum/Result.lean @@ -26,7 +26,7 @@ or is either `true` or `false`. universe u variable {α : Type u} -open Lean hiding Rat mkRat +open Lean open Lean.Meta Qq Lean.Elab Term namespace Mathlib diff --git a/Mathlib/Tactic/Polyrith.lean b/Mathlib/Tactic/Polyrith.lean index 50e42c8eecbd1..91b368722375e 100644 --- a/Mathlib/Tactic/Polyrith.lean +++ b/Mathlib/Tactic/Polyrith.lean @@ -60,7 +60,7 @@ remember to force recompilation of any files that call `polyrith`. -/ namespace Mathlib.Tactic.Polyrith -open Lean hiding Rat +open Lean open Meta Ring Qq PrettyPrinter AtomM initialize registerTraceClass `Meta.Tactic.polyrith diff --git a/Mathlib/Tactic/Positivity/Core.lean b/Mathlib/Tactic/Positivity/Core.lean index 0b6a352c4ae01..a56d312db10c5 100644 --- a/Mathlib/Tactic/Positivity/Core.lean +++ b/Mathlib/Tactic/Positivity/Core.lean @@ -20,7 +20,7 @@ The actual behavior is in `@[positivity]`-tagged definitions in `Tactic.Positivi and elsewhere. -/ -open Lean hiding Rat +open Lean open Lean.Meta Qq Lean.Elab Term /-- Attribute for identifying `positivity` extensions. -/ @@ -71,9 +71,6 @@ def mkPositivityExt (n : Name) : ImportM PositivityExt := do let { env, opts, .. } ← read IO.ofExcept <| unsafe env.evalConstCheck PositivityExt opts ``PositivityExt n -/-- Configuration for `DiscrTree`. -/ -def discrTreeConfig : WhnfCoreConfig := {} - /-- Each `positivity` extension is labelled with a collection of patterns which determine the expressions to which it should be applied. -/ abbrev Entry := Array (Array DiscrTree.Key) × Name @@ -113,7 +110,7 @@ initialize registerBuiltinAttribute { let e ← elabTerm stx none let (_, _, e) ← lambdaMetaTelescope (← mkLambdaFVars (← getLCtx).getFVars e) return e - DiscrTree.mkPath e discrTreeConfig + DiscrTree.mkPath e setEnv <| positivityExt.addEntry env ((keys, declName), ext) | _ => throwUnsupportedSyntax } @@ -318,7 +315,7 @@ def orElse {e : Q($α)} (t₁ : Strictness zα pα e) (t₂ : MetaM (Strictness def core (e : Q($α)) : MetaM (Strictness zα pα e) := do let mut result := .none trace[Tactic.positivity] "trying to prove positivity of {e}" - for ext in ← (positivityExt.getState (← getEnv)).2.getMatch e discrTreeConfig do + for ext in ← (positivityExt.getState (← getEnv)).2.getMatch e do try result ← orElse result <| ext.eval zα pα e catch err => diff --git a/Mathlib/Tactic/Propose.lean b/Mathlib/Tactic/Propose.lean index 4169210c6c5ce..debb88c19ec1b 100644 --- a/Mathlib/Tactic/Propose.lean +++ b/Mathlib/Tactic/Propose.lean @@ -39,9 +39,6 @@ open Lean Meta Batteries.Tactic Tactic.TryThis initialize registerTraceClass `Tactic.propose -/-- Configuration for `DiscrTree`. -/ -def discrTreeConfig : WhnfCoreConfig := {} - initialize proposeLemmas : DeclCache (DiscrTree Name) ← DeclCache.mk "have?: init cache" failure {} fun name constInfo lemmas => do if constInfo.isUnsafe then return lemmas @@ -50,7 +47,7 @@ initialize proposeLemmas : DeclCache (DiscrTree Name) ← let (mvars, _, _) ← forallMetaTelescope constInfo.type let mut lemmas := lemmas for m in mvars do - lemmas ← lemmas.insertIfSpecific (← inferType m) name discrTreeConfig + lemmas ← lemmas.insertIfSpecific (← inferType m) name pure lemmas open Lean.Meta.SolveByElim in @@ -80,7 +77,7 @@ def propose (lemmas : DiscrTree Name) (type : Expr) (required : Array Expr) (solveByElimDepth := 15) : MetaM (Array (Name × Expr)) := do guard !required.isEmpty let ty ← whnfR (← instantiateMVars (← inferType required[0]!)) - let candidates ← lemmas.getMatch ty discrTreeConfig + let candidates ← lemmas.getMatch ty candidates.filterMapM fun lem : Name => try trace[Tactic.propose] "considering {lem}" diff --git a/Mathlib/Tactic/PushNeg.lean b/Mathlib/Tactic/PushNeg.lean index 39b7ff1d2cd6b..4c59bb174597f 100644 --- a/Mathlib/Tactic/PushNeg.lean +++ b/Mathlib/Tactic/PushNeg.lean @@ -144,10 +144,9 @@ partial def transformNegation (e : Expr) : SimpM Simp.Step := do /-- Common entry point to `push_neg` as a conv. -/ def pushNegCore (tgt : Expr) : MetaM Simp.Result := do - let myctx : Simp.Context := - { config := { eta := true, zeta := false, proj := false }, - simpTheorems := #[ ] - congrTheorems := (← getSimpCongrTheorems) } + let myctx : Simp.Context ← Simp.mkContext { eta := true, zeta := false, proj := false } + (simpTheorems := #[ ]) + (congrTheorems := (← getSimpCongrTheorems)) (·.1) <$> Simp.main tgt myctx (methods := { pre := transformNegation }) /-- diff --git a/Mathlib/Tactic/ReduceModChar.lean b/Mathlib/Tactic/ReduceModChar.lean index a7689ecfbbe80..ed98906d7949f 100644 --- a/Mathlib/Tactic/ReduceModChar.lean +++ b/Mathlib/Tactic/ReduceModChar.lean @@ -251,11 +251,8 @@ partial def derive (expensive := false) (e : Expr) : MetaM Simp.Result := do let ext ← match ext? with | some ext => pure ext | none => throwError "internal error: reduce_mod_char not registered as simp extension" - let ctx : Simp.Context := { - config := config, - congrTheorems := congrTheorems, - simpTheorems := #[← ext.getTheorems] - } + let ctx ← Simp.mkContext config (congrTheorems := congrTheorems) + (simpTheorems := #[← ext.getTheorems]) let discharge := Mathlib.Meta.NormNum.discharge ctx let r : Simp.Result := {expr := e} let pre := Simp.preDefault #[] >> fun e => diff --git a/Mathlib/Tactic/Relation/Rfl.lean b/Mathlib/Tactic/Relation/Rfl.lean index b35a56bd7c5c9..2abf31b41b4df 100644 --- a/Mathlib/Tactic/Relation/Rfl.lean +++ b/Mathlib/Tactic/Relation/Rfl.lean @@ -36,7 +36,7 @@ def _root_.Lean.Expr.relSidesIfRefl? (e : Expr) : MetaM (Option (Name × Expr × if let some (_, lhs, _, rhs) := e.heq? then return (``HEq, lhs, rhs) if let .app (.app rel lhs) rhs := e then - unless (← (reflExt.getState (← getEnv)).getMatch rel reflExt.config).isEmpty do + unless (← (reflExt.getState (← getEnv)).getMatch rel).isEmpty do match rel.getAppFn.constName? with | some n => return some (n, lhs, rhs) | none => return none diff --git a/Mathlib/Tactic/Relation/Symm.lean b/Mathlib/Tactic/Relation/Symm.lean index 8d33854268714..aa240b55b3d28 100644 --- a/Mathlib/Tactic/Relation/Symm.lean +++ b/Mathlib/Tactic/Relation/Symm.lean @@ -27,7 +27,7 @@ def _root_.Lean.Expr.relSidesIfSymm? (e : Expr) : MetaM (Option (Name × Expr × if let some (_, lhs, _, rhs) := e.heq? then return (``HEq, lhs, rhs) if let .app (.app rel lhs) rhs := e then - unless (← (symmExt.getState (← getEnv)).getMatch rel symmExt.config).isEmpty do + unless (← (symmExt.getState (← getEnv)).getMatch rel).isEmpty do match rel.getAppFn.constName? with | some n => return some (n, lhs, rhs) | none => return none diff --git a/Mathlib/Tactic/Ring/RingNF.lean b/Mathlib/Tactic/Ring/RingNF.lean index 6b9c13c7cca7a..095a8b819b8d4 100644 --- a/Mathlib/Tactic/Ring/RingNF.lean +++ b/Mathlib/Tactic/Ring/RingNF.lean @@ -19,7 +19,7 @@ such as `sin (x + y) + sin (y + x) = 2 * sin (x + y)`. -/ namespace Mathlib.Tactic -open Lean hiding Rat +open Lean open Qq Meta namespace Ring @@ -133,10 +133,9 @@ Runs a tactic in the `RingNF.M` monad, given initial data: -/ partial def M.run {α : Type} (s : IO.Ref AtomM.State) (cfg : RingNF.Config) (x : M α) : MetaM α := do - let ctx := { - simpTheorems := #[← Elab.Tactic.simpOnlyBuiltins.foldlM (·.addConst ·) {}] - congrTheorems := ← getSimpCongrTheorems - config.singlePass := cfg.mode matches .raw } + let ctx ← Simp.mkContext { singlePass := cfg.mode matches .raw } + (simpTheorems := #[← Elab.Tactic.simpOnlyBuiltins.foldlM (·.addConst ·) {}]) + (congrTheorems := ← getSimpCongrTheorems) let simp ← match cfg.mode with | .raw => pure pure | .SOP => @@ -145,7 +144,7 @@ partial def M.run ``_root_.pow_one, ``mul_neg, ``add_neg].foldlM (·.addConst ·) thms let thms ← [``nat_rawCast_0, ``nat_rawCast_1, ``nat_rawCast_2, ``int_rawCast_neg, ``rat_rawCast_neg, ``rat_rawCast_pos].foldlM (·.addConst · (post := false)) thms - let ctx' := { ctx with simpTheorems := #[thms] } + let ctx' := ctx.setSimpTheorems #[thms] pure fun r' : Simp.Result ↦ do r'.mkEqTrans (← Simp.main r'.expr ctx' (methods := Lean.Meta.Simp.mkDefaultMethodsCore {})).1 let nctx := { ctx, simp } @@ -260,9 +259,17 @@ example (x : ℕ) (h : x * 2 > 5): x + x > 5 := by ring; assumption -- suggests ``` -/ macro (name := ring) "ring" : tactic => - `(tactic| first | ring1 | try_this ring_nf) + `(tactic| first | ring1 | try_this ring_nf + "\n\nThe `ring` tactic failed to close the goal. Use `ring_nf` to obtain a normal form. + \nNote that `ring` works primarily in *commutative* rings. \ + If you have a noncommutative ring, abelian group or module, consider using \ + `noncomm_ring`, `abel` or `module` instead.") @[inherit_doc ring] macro "ring!" : tactic => - `(tactic| first | ring1! | try_this ring_nf!) + `(tactic| first | ring1! | try_this ring_nf! + "\n\nThe `ring!` tactic failed to close the goal. Use `ring_nf!` to obtain a normal form. + \nNote that `ring!` works primarily in *commutative* rings. \ + If you have a noncommutative ring, abelian group or module, consider using \ + `noncomm_ring`, `abel` or `module` instead.") /-- The tactic `ring` evaluates expressions in *commutative* (semi)rings. @@ -271,9 +278,17 @@ This is the conv tactic version, which rewrites a target which is a ring equalit See also the `ring` tactic. -/ macro (name := ringConv) "ring" : conv => - `(conv| first | discharge => ring1 | try_this ring_nf) + `(conv| first | discharge => ring1 | try_this ring_nf + "\n\nThe `ring` tactic failed to close the goal. Use `ring_nf` to obtain a normal form. + \nNote that `ring` works primarily in *commutative* rings. \ + If you have a noncommutative ring, abelian group or module, consider using \ + `noncomm_ring`, `abel` or `module` instead.") @[inherit_doc ringConv] macro "ring!" : conv => - `(conv| first | discharge => ring1! | try_this ring_nf!) + `(conv| first | discharge => ring1! | try_this ring_nf! + "\n\nThe `ring!` tactic failed to close the goal. Use `ring_nf!` to obtain a normal form. + \nNote that `ring!` works primarily in *commutative* rings. \ + If you have a noncommutative ring, abelian group or module, consider using \ + `noncomm_ring`, `abel` or `module` instead.") end RingNF diff --git a/Mathlib/Tactic/SimpIntro.lean b/Mathlib/Tactic/SimpIntro.lean index f2f3ff6f8b497..a816ba1df65b2 100644 --- a/Mathlib/Tactic/SimpIntro.lean +++ b/Mathlib/Tactic/SimpIntro.lean @@ -31,7 +31,7 @@ partial def simpIntroCore (g : MVarId) (ctx : Simp.Context) (simprocs : Simp.Sim let withFVar := fun (fvar, g) ↦ g.withContext do Term.addLocalVarInfo var (mkFVar fvar) let simpTheorems ← ctx.simpTheorems.addTheorem (.fvar fvar) (.fvar fvar) - simpIntroCore g { ctx with simpTheorems } simprocs discharge? more ids' + simpIntroCore g (ctx.setSimpTheorems simpTheorems) simprocs discharge? more ids' match t with | .letE .. => withFVar (← g.intro n) | .forallE (body := body) .. => diff --git a/Mathlib/Tactic/Simps/Basic.lean b/Mathlib/Tactic/Simps/Basic.lean index dac4370d3235c..9bff6a59a5119 100644 --- a/Mathlib/Tactic/Simps/Basic.lean +++ b/Mathlib/Tactic/Simps/Basic.lean @@ -82,10 +82,9 @@ def mkSimpContextResult (cfg : Meta.Simp.Config := {}) (simpOnly := false) (kind getSimpTheorems let simprocs := #[← if simpOnly then pure {} else Simp.getSimprocs] let congrTheorems ← getSimpCongrTheorems - let ctx : Simp.Context := { - config := cfg - simpTheorems := #[simpTheorems], congrTheorems - } + let ctx : Simp.Context ← Simp.mkContext cfg + (simpTheorems := #[simpTheorems]) + (congrTheorems := congrTheorems) if !hasStar then return { ctx, simprocs, dischargeWrapper } else @@ -94,7 +93,7 @@ def mkSimpContextResult (cfg : Meta.Simp.Config := {}) (simpOnly := false) (kind for h in hs do unless simpTheorems.isErased (.fvar h) do simpTheorems ← simpTheorems.addTheorem (.fvar h) (← h.getDecl).toExpr - let ctx := { ctx with simpTheorems } + let ctx := ctx.setSimpTheorems simpTheorems return { ctx, simprocs, dischargeWrapper } /-- Make `Simp.Context` giving data instead of Syntax. Doesn't support arguments. diff --git a/Mathlib/Tactic/SplitIfs.lean b/Mathlib/Tactic/SplitIfs.lean index 49287e1c5ec75..64e0fa989bcac 100644 --- a/Mathlib/Tactic/SplitIfs.lean +++ b/Mathlib/Tactic/SplitIfs.lean @@ -75,7 +75,7 @@ private def discharge? (e : Expr) : SimpM (Option Expr) := do -/ private def reduceIfsAt (loc : Location) : TacticM Unit := do let ctx ← SplitIf.getSimpContext - let ctx := { ctx with config := { ctx.config with failIfUnchanged := false } } + let ctx := ctx.setFailIfUnchanged false let _ ← simpLocation ctx (← ({} : Simp.SimprocsArray).add `reduceCtorEq false) discharge? loc pure () diff --git a/Mathlib/Tactic/Spread.lean b/Mathlib/Tactic/Spread.lean index 0252a2fa396db..36c7fb615c6b7 100644 --- a/Mathlib/Tactic/Spread.lean +++ b/Mathlib/Tactic/Spread.lean @@ -66,8 +66,6 @@ macro_rules spreads := spreads.push arg else newFields := newFields.push field - | `(structInstFieldAbbrev| $_:ident) => - newFields := newFields.push field | _ => throwUnsupported diff --git a/Mathlib/Tactic/ToAdditive/Frontend.lean b/Mathlib/Tactic/ToAdditive/Frontend.lean index 25e3af975e0bf..b0278e30a9e9d 100644 --- a/Mathlib/Tactic/ToAdditive/Frontend.lean +++ b/Mathlib/Tactic/ToAdditive/Frontend.lean @@ -866,7 +866,7 @@ def additivizeLemmas {m : Type → Type} [Monad m] [MonadError m] [MonadLiftT Co for (nm, lemmas) in names.zip auxLemmas do unless lemmas.size == nLemmas do throwError "{names[0]!} and {nm} do not generate the same number of {desc}." - for (srcLemmas, tgtLemmas) in auxLemmas.zip <| auxLemmas.eraseIdx 0 do + for (srcLemmas, tgtLemmas) in auxLemmas.zip <| auxLemmas.eraseIdx! 0 do for (srcLemma, tgtLemma) in srcLemmas.zip tgtLemmas do insertTranslation srcLemma tgtLemma diff --git a/Mathlib/Tactic/TryThis.lean b/Mathlib/Tactic/TryThis.lean index 3d4814c3d4087..f34ea59970cb9 100644 --- a/Mathlib/Tactic/TryThis.lean +++ b/Mathlib/Tactic/TryThis.lean @@ -18,13 +18,17 @@ namespace Mathlib.Tactic open Lean /-- Produces the text `Try this: ` with the given tactic, and then executes it. -/ -elab tk:"try_this" tac:tactic : tactic => do +elab tk:"try_this" tac:tactic info:(str)? : tactic => do Elab.Tactic.evalTactic tac - Meta.Tactic.TryThis.addSuggestion tk tac (origSpan? := ← getRef) + Meta.Tactic.TryThis.addSuggestion tk + { suggestion := tac, postInfo? := TSyntax.getString <$> info } + (origSpan? := ← getRef) /-- Produces the text `Try this: ` with the given conv tactic, and then executes it. -/ -elab tk:"try_this" tac:conv : conv => do +elab tk:"try_this" tac:conv info:(str)? : conv => do Elab.Tactic.evalTactic tac - Meta.Tactic.TryThis.addSuggestion tk tac (origSpan? := ← getRef) + Meta.Tactic.TryThis.addSuggestion tk + { suggestion := tac, postInfo? := TSyntax.getString <$> info } + (origSpan? := ← getRef) end Mathlib.Tactic diff --git a/Mathlib/Tactic/Variable.lean b/Mathlib/Tactic/Variable.lean index c506333c3c075..3f885e361c071 100644 --- a/Mathlib/Tactic/Variable.lean +++ b/Mathlib/Tactic/Variable.lean @@ -159,7 +159,7 @@ partial def completeBinders' (maxSteps : Nat) (gas : Nat) (binders : TSyntaxArray ``bracketedBinder) (toOmit : Array Bool) (i : Nat) : TermElabM (TSyntaxArray ``bracketedBinder × Array Bool) := do - if 0 < gas && i < binders.size then + if h : 0 < gas ∧ i < binders.size then let binder := binders[i]! trace[«variable?»] "\ Have {(← getLCtx).getFVarIds.size} fvars and {(← getLocalInstances).size} local instances. \ @@ -176,7 +176,7 @@ partial def completeBinders' (maxSteps : Nat) (gas : Nat) 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' + let binders := binders.insertIdx i binder' completeBinders' maxSteps (gas - 1) checkRedundant binders toOmit i else let lctx ← getLCtx diff --git a/Mathlib/Tactic/WLOG.lean b/Mathlib/Tactic/WLOG.lean index 461949d04ab7b..cad9a19bf5bfd 100644 --- a/Mathlib/Tactic/WLOG.lean +++ b/Mathlib/Tactic/WLOG.lean @@ -77,7 +77,8 @@ def _root_.Lean.MVarId.wlog (goal : MVarId) (h : Option Name) (P : Expr) 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 + let HType ← withFreshCache do + mkAuxMVarType lctx (revertedFVars.map Expr.fvar) .natural HSuffix (usedLetOnly := true) return (revertedFVars, HType)) { preserveOrder := false, mainModule := ctx.mainModule } /- Set up the goal which will suppose `h`; this begins as a goal with type H (hence HExpr), and h diff --git a/Mathlib/Testing/Plausible/Functions.lean b/Mathlib/Testing/Plausible/Functions.lean index a9bdf24d8ccb4..ba4209766edf6 100644 --- a/Mathlib/Testing/Plausible/Functions.lean +++ b/Mathlib/Testing/Plausible/Functions.lean @@ -202,7 +202,7 @@ theorem List.applyId_zip_eq [DecidableEq α] {xs ys : List α} (h₀ : List.Nodu simp only [getElem?_cons_succ, zip_cons_cons, applyId_cons] at h₂ ⊢ rw [if_neg] · apply xs_ih <;> solve_by_elim [Nat.succ.inj] - · apply h₀; apply List.getElem?_mem h₂ + · apply h₀; apply List.mem_of_getElem? h₂ theorem applyId_mem_iff [DecidableEq α] {xs ys : List α} (h₀ : List.Nodup xs) (h₁ : xs ~ ys) (x : α) : List.applyId.{u} (xs.zip ys) x ∈ ys ↔ x ∈ xs := by diff --git a/Mathlib/Topology/Algebra/ConstMulAction.lean b/Mathlib/Topology/Algebra/ConstMulAction.lean index 10007257a47c5..cd4bdb42717b6 100644 --- a/Mathlib/Topology/Algebra/ConstMulAction.lean +++ b/Mathlib/Topology/Algebra/ConstMulAction.lean @@ -8,9 +8,9 @@ import Mathlib.Algebra.Order.Group.Synonym import Mathlib.Data.Set.Pointwise.SMul import Mathlib.GroupTheory.GroupAction.Defs import Mathlib.Topology.Algebra.Constructions +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.Bases import Mathlib.Topology.Homeomorph -import Mathlib.Topology.Support /-! # Monoid actions continuous in the second variable diff --git a/Mathlib/Topology/Algebra/Group/Basic.lean b/Mathlib/Topology/Algebra/Group/Basic.lean index 4b003dcf49f11..6746a7d253f9f 100644 --- a/Mathlib/Topology/Algebra/Group/Basic.lean +++ b/Mathlib/Topology/Algebra/Group/Basic.lean @@ -233,6 +233,9 @@ theorem ContinuousWithinAt.inv (hf : ContinuousWithinAt f s x) : ContinuousWithinAt (fun x => (f x)⁻¹) s x := Filter.Tendsto.inv hf +@[to_additive] +instance OrderDual.instContinuousInv : ContinuousInv Gᵒᵈ := ‹ContinuousInv G› + @[to_additive] instance Prod.continuousInv [TopologicalSpace H] [Inv H] [ContinuousInv H] : ContinuousInv (G × H) := @@ -536,6 +539,9 @@ end OrderedCommGroup instance [TopologicalSpace H] [Group H] [TopologicalGroup H] : TopologicalGroup (G × H) where continuous_inv := continuous_inv.prodMap continuous_inv +@[to_additive] +instance OrderDual.instTopologicalGroup : TopologicalGroup Gᵒᵈ where + @[to_additive] instance Pi.topologicalGroup {C : β → Type*} [∀ b, TopologicalSpace (C b)] [∀ b, Group (C b)] [∀ b, TopologicalGroup (C b)] : TopologicalGroup (∀ b, C b) where diff --git a/Mathlib/Topology/Algebra/Group/OpenMapping.lean b/Mathlib/Topology/Algebra/Group/OpenMapping.lean index e3e52fc76e603..f2e6dce2efef1 100644 --- a/Mathlib/Topology/Algebra/Group/OpenMapping.lean +++ b/Mathlib/Topology/Algebra/Group/OpenMapping.lean @@ -114,6 +114,6 @@ theorem MonoidHom.isOpenMap_of_sigmaCompact let A : MulAction G H := MulAction.compHom _ f have : ContinuousSMul G H := continuousSMul_compHom h'f have : IsPretransitive G H := isPretransitive_compHom hf - have : f = (fun (g : G) ↦ g • (1 : H)) := by simp [MulAction.compHom_smul_def] + have : f = (fun (g : G) ↦ g • (1 : H)) := by simp [A, MulAction.compHom_smul_def] rw [this] exact isOpenMap_smul_of_sigmaCompact _ diff --git a/Mathlib/Topology/Algebra/Indicator.lean b/Mathlib/Topology/Algebra/Indicator.lean new file mode 100644 index 0000000000000..189c9d6f29038 --- /dev/null +++ b/Mathlib/Topology/Algebra/Indicator.lean @@ -0,0 +1,38 @@ +/- +Copyright (c) 2024 PFR contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: PFR contributors +-/ +import Mathlib.Algebra.Group.Indicator +import Mathlib.Topology.ContinuousOn + +/-! +# Continuity of indicator functions +-/ + +open Set +open scoped Topology + +variable {α β : Type*} [TopologicalSpace α] [TopologicalSpace β] {f : α → β} {s : Set α} [One β] + +@[to_additive] +lemma continuous_mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf : ContinuousOn f (closure s)) : + Continuous (mulIndicator s f) := by + classical exact continuous_piecewise hs hf continuousOn_const + +@[to_additive] +protected lemma Continuous.mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf : Continuous f) : + Continuous (mulIndicator s f) := by + classical exact hf.piecewise hs continuous_const + +@[to_additive] +theorem ContinuousOn.continuousAt_mulIndicator (hf : ContinuousOn f (interior s)) {x : α} + (hx : x ∉ frontier s) : + ContinuousAt (s.mulIndicator f) x := by + rw [← Set.mem_compl_iff, compl_frontier_eq_union_interior] at hx + obtain h | h := hx + · have hs : interior s ∈ 𝓝 x := mem_interior_iff_mem_nhds.mp (by rwa [interior_interior]) + exact ContinuousAt.congr (hf.continuousAt hs) <| Filter.eventuallyEq_iff_exists_mem.mpr + ⟨interior s, hs, Set.eqOn_mulIndicator.symm.mono interior_subset⟩ + · exact ContinuousAt.congr continuousAt_const <| Filter.eventuallyEq_iff_exists_mem.mpr + ⟨sᶜ, mem_interior_iff_mem_nhds.mp h, Set.eqOn_mulIndicator'.symm⟩ diff --git a/Mathlib/Topology/Algebra/Module/LinearPMap.lean b/Mathlib/Topology/Algebra/Module/LinearPMap.lean index dc97ddf2c8859..1fccf24ee319b 100644 --- a/Mathlib/Topology/Algebra/Module/LinearPMap.lean +++ b/Mathlib/Topology/Algebra/Module/LinearPMap.lean @@ -155,7 +155,7 @@ theorem closureHasCore (f : E →ₗ.[R] F) : f.closure.HasCore f.domain := by intro hx exact f.le_closure.1 hx let z : f.closure.domain := ⟨y.1, f.le_closure.1 y.2⟩ - have hyz : (y : E) = z := by simp + have hyz : (y : E) = z := by simp [z] rw [f.le_closure.2 hyz] exact domRestrict_apply (hxy.trans hyz) diff --git a/Mathlib/Topology/Algebra/Module/LocallyConvex.lean b/Mathlib/Topology/Algebra/Module/LocallyConvex.lean index dbed63cbce723..8d72fea405dff 100644 --- a/Mathlib/Topology/Algebra/Module/LocallyConvex.lean +++ b/Mathlib/Topology/Algebra/Module/LocallyConvex.lean @@ -91,10 +91,21 @@ theorem locallyConvexSpace_iff_exists_convex_subset_zero : (locallyConvexSpace_iff_zero 𝕜 E).trans hasBasis_self -- see Note [lower instance priority] -instance (priority := 100) LocallyConvexSpace.toLocallyConnectedSpace [Module ℝ E] - [ContinuousSMul ℝ E] [LocallyConvexSpace ℝ E] : LocallyConnectedSpace E := - locallyConnectedSpace_of_connected_bases _ _ - (fun x => @LocallyConvexSpace.convex_basis ℝ _ _ _ _ _ _ x) fun _ _ hs => hs.2.isPreconnected +instance (priority := 100) LocallyConvexSpace.toLocPathConnectedSpace [Module ℝ E] + [ContinuousSMul ℝ E] [LocallyConvexSpace ℝ E] : LocPathConnectedSpace E := + .of_bases (fun x ↦ convex_basis (𝕜 := ℝ) x) + fun _ _ hs ↦ hs.2.isPathConnected <| nonempty_of_mem <| mem_of_mem_nhds hs.1 + +/-- Convex subsets of locally convex spaces are locally path-connected. -/ +theorem Convex.locPathConnectedSpace [Module ℝ E] [ContinuousSMul ℝ E] [LocallyConvexSpace ℝ E] + {S : Set E} (hS : Convex ℝ S) : LocPathConnectedSpace S := by + refine ⟨fun x ↦ ⟨fun s ↦ ⟨fun hs ↦ ?_, fun ⟨t, ht⟩ ↦ mem_of_superset ht.1.1 ht.2⟩⟩⟩ + let ⟨t, ht⟩ := (mem_nhds_subtype S x s).mp hs + let ⟨t', ht'⟩ := (LocallyConvexSpace.convex_basis (𝕜 := ℝ) x.1).mem_iff.mp ht.1 + refine ⟨(↑) ⁻¹' t', ⟨?_, ?_⟩, (preimage_mono ht'.2).trans ht.2⟩ + · exact continuousAt_subtype_val.preimage_mem_nhds ht'.1.1 + · refine Subtype.preimage_coe_self_inter _ _ ▸ IsPathConnected.preimage_coe ?_ inter_subset_left + exact (hS.inter ht'.1.2).isPathConnected ⟨x, x.2, mem_of_mem_nhds ht'.1.1⟩ end Module diff --git a/Mathlib/Topology/Algebra/PontryaginDual.lean b/Mathlib/Topology/Algebra/PontryaginDual.lean index 4229049cf7321..2b24a7b06909d 100644 --- a/Mathlib/Topology/Algebra/PontryaginDual.lean +++ b/Mathlib/Topology/Algebra/PontryaginDual.lean @@ -73,7 +73,7 @@ instance [LocallyCompactSpace H] : LocallyCompactSpace (PontryaginDual H) := by refine lt_of_lt_of_le ht ?_ rw [div_le_iff₀' (pow_pos two_pos _), ← div_le_iff₀ hx] refine (Nat.le_ceil (Real.pi / x)).trans ?_ - exact_mod_cast (Nat.le_succ _).trans (Nat.lt_two_pow _).le + exact_mod_cast (Nat.le_succ _).trans Nat.lt_two_pow_self.le variable {A B C G} diff --git a/Mathlib/Topology/Algebra/ProperAction/Basic.lean b/Mathlib/Topology/Algebra/ProperAction/Basic.lean index 5b68b2d2d0d6f..12dc275ef0e31 100644 --- a/Mathlib/Topology/Algebra/ProperAction/Basic.lean +++ b/Mathlib/Topology/Algebra/ProperAction/Basic.lean @@ -129,15 +129,15 @@ theorem t2Space_of_properSMul_of_t2Group [h_proper : ProperSMul G X] [T2Space G] have proper_f : IsProperMap f := by refine IsClosedEmbedding.isProperMap ⟨?_, ?_⟩ · let g := fun gx : G × X ↦ gx.2 - have : Function.LeftInverse g f := fun x ↦ by simp + have : Function.LeftInverse g f := fun x ↦ by simp [f, g] exact this.isEmbedding (by fun_prop) (by fun_prop) - · have : range f = ({1} ×ˢ univ) := by simp + · have : range f = ({1} ×ˢ univ) := by simp [f] rw [this] exact isClosed_singleton.prod isClosed_univ rw [t2_iff_isClosed_diagonal] let g := fun gx : G × X ↦ (gx.1 • gx.2, gx.2) have proper_g : IsProperMap g := (properSMul_iff G X).1 h_proper - have : g ∘ f = fun x ↦ (x, x) := by ext x <;> simp + have : g ∘ f = fun x ↦ (x, x) := by ext x <;> simp [f, g] have range_gf : range (g ∘ f) = diagonal X := by simp [this] rw [← range_gf] exact (proper_f.comp proper_g).isClosed_range diff --git a/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean index 1f2427e29b56f..6790b8c087127 100644 --- a/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean +++ b/Mathlib/Topology/Algebra/SeparationQuotient/Basic.lean @@ -85,7 +85,7 @@ variable {M : Type*} [TopologicalSpace M] @[to_additive] instance instMul [Mul M] [ContinuousMul M] : Mul (SeparationQuotient M) where - mul := Quotient.map₂' (· * ·) fun _ _ h₁ _ _ h₂ ↦ Inseparable.mul h₁ h₂ + mul := Quotient.map₂ (· * ·) fun _ _ h₁ _ _ h₂ ↦ Inseparable.mul h₁ h₂ @[to_additive (attr := simp)] theorem mk_mul [Mul M] [ContinuousMul M] (a b : M) : mk (a * b) = mk a * mk b := rfl @@ -168,7 +168,7 @@ instance instInvOneClass [InvOneClass G] [ContinuousInv G] : @[to_additive] instance instDiv [Div G] [ContinuousDiv G] : Div (SeparationQuotient G) where - div := Quotient.map₂' (· / ·) fun _ _ h₁ _ _ h₂ ↦ (Inseparable.prod h₁ h₂).map continuous_div' + div := Quotient.map₂ (· / ·) fun _ _ h₁ _ _ h₂ ↦ (Inseparable.prod h₁ h₂).map continuous_div' @[to_additive (attr := simp)] theorem mk_div [Div G] [ContinuousDiv G] (x y : G) : mk (x / y) = mk x / mk y := rfl diff --git a/Mathlib/Topology/Support.lean b/Mathlib/Topology/Algebra/Support.lean similarity index 100% rename from Mathlib/Topology/Support.lean rename to Mathlib/Topology/Algebra/Support.lean diff --git a/Mathlib/Topology/Algebra/UniformGroup/Defs.lean b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean index 3455d9f14d056..5b6a3aeeb9ff2 100644 --- a/Mathlib/Topology/Algebra/UniformGroup/Defs.lean +++ b/Mathlib/Topology/Algebra/UniformGroup/Defs.lean @@ -406,19 +406,11 @@ variable {G} @[to_additive] -- Porting note: renamed theorem to conform to naming convention theorem comm_topologicalGroup_is_uniform : UniformGroup G := by - have : - Tendsto - ((fun p : G × G => p.1 / p.2) ∘ fun p : (G × G) × G × G => (p.1.2 / p.1.1, p.2.2 / p.2.1)) - (comap (fun p : (G × G) × G × G => (p.1.2 / p.1.1, p.2.2 / p.2.1)) ((𝓝 1).prod (𝓝 1))) - (𝓝 (1 / 1)) := - (tendsto_fst.div' tendsto_snd).comp tendsto_comap constructor - rw [UniformContinuous, uniformity_prod_eq_prod, tendsto_map'_iff, uniformity_eq_comap_nhds_one' G, - tendsto_comap_iff, prod_comap_comap_eq] - simp only [Function.comp_def, div_eq_mul_inv, mul_inv_rev, inv_inv, mul_comm, mul_left_comm] at * - simp only [inv_one, mul_one, ← mul_assoc] at this - simp_rw [← mul_assoc, mul_comm] - assumption + simp only [UniformContinuous, uniformity_prod_eq_prod, uniformity_eq_comap_nhds_one', + tendsto_comap_iff, tendsto_map'_iff, prod_comap_comap_eq, Function.comp_def, + div_div_div_comm _ (Prod.snd (Prod.snd _)), ← nhds_prod_eq, Prod.mk_one_one] + exact (continuous_div'.tendsto' 1 1 (div_one 1)).comp tendsto_comap open Set diff --git a/Mathlib/Topology/Bases.lean b/Mathlib/Topology/Bases.lean index 4db6b21371950..969cd3b6dd3fa 100644 --- a/Mathlib/Topology/Bases.lean +++ b/Mathlib/Topology/Bases.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Mario Carneiro -/ import Mathlib.Data.Set.Constructions +import Mathlib.Order.Filter.AtTopBot.CountablyGenerated import Mathlib.Topology.Constructions import Mathlib.Topology.ContinuousOn diff --git a/Mathlib/Topology/Category/Profinite/Nobeling.lean b/Mathlib/Topology/Category/Profinite/Nobeling.lean index 42749f3df74e4..c244872abc715 100644 --- a/Mathlib/Topology/Category/Profinite/Nobeling.lean +++ b/Mathlib/Topology/Category/Profinite/Nobeling.lean @@ -1055,10 +1055,9 @@ theorem Products.limitOrdinal (l : Products I) : l.isGood (π C (ord I · < o)) ∃ (o' : Ordinal), o' < o ∧ l.isGood (π C (ord I · < o')) := by refine ⟨fun h ↦ ?_, fun ⟨o', ⟨ho', hl⟩⟩ ↦ isGood_mono C (le_of_lt ho') hl⟩ use Finset.sup l.val.toFinset (fun a ↦ Order.succ (ord I a)) - have ha : ⊥ < o := by rw [Ordinal.bot_eq_zero, Ordinal.pos_iff_ne_zero]; exact ho.1 have hslt : Finset.sup l.val.toFinset (fun a ↦ Order.succ (ord I a)) < o := by - simp only [Finset.sup_lt_iff ha, List.mem_toFinset] - exact fun b hb ↦ ho.2 _ (prop_of_isGood C (ord I · < o) h b hb) + simp only [Finset.sup_lt_iff ho.pos, List.mem_toFinset] + exact fun b hb ↦ ho.succ_lt (prop_of_isGood C (ord I · < o) h b hb) refine ⟨hslt, fun he ↦ h ?_⟩ have hlt : ∀ i ∈ l.val, ord I i < Finset.sup l.val.toFinset (fun a ↦ Order.succ (ord I a)) := by intro i hi @@ -1343,7 +1342,7 @@ theorem CC_exact {f : LocallyConstant C ℤ} (hf : Linear_CC' C hsC ho f = 0) : cases' hx with hx₀ hx₁ · have hx₀' : ProjRestrict C (ord I · < o) ⟨x, hx⟩ = x := by simpa only [ProjRestrict, Set.MapsTo.val_restrict_apply] using C0_projOrd C hsC ho hx₀ - simp only [πs_apply_apply, hx₀', hx₀, LocallyConstant.piecewise'_apply_left, + simp only [C₀C, πs_apply_apply, hx₀', hx₀, LocallyConstant.piecewise'_apply_left, LocallyConstant.coe_comap, ContinuousMap.coe_mk, Function.comp_apply] · have hx₁' : (ProjRestrict C (ord I · < o) ⟨x, hx⟩).val ∈ π (C1 C ho) (ord I · < o) := by simpa only [ProjRestrict, Set.MapsTo.val_restrict_apply] using ⟨x, hx₁, rfl⟩ @@ -1354,14 +1353,14 @@ theorem CC_exact {f : LocallyConstant C ℤ} (hf : Linear_CC' C hsC ho f = 0) : exact C1_projOrd C hsC ho hx₁ variable (o) in -theorem succ_mono : CategoryTheory.Mono (ModuleCat.asHom (πs C o)) := by +theorem succ_mono : CategoryTheory.Mono (ModuleCat.ofHom (πs C o)) := by rw [ModuleCat.mono_iff_injective] exact injective_πs _ _ include hC in theorem succ_exact : - (ShortComplex.mk (ModuleCat.asHom (πs C o)) (ModuleCat.asHom (Linear_CC' C hsC ho)) - (by ext; apply CC_comp_zero)).Exact := by + (ShortComplex.mk (ModuleCat.ofHom (πs C o)) (ModuleCat.ofHom (Linear_CC' C hsC ho)) + (by ext : 2; apply CC_comp_zero)).Exact := by rw [ShortComplex.moduleCat_exact_iff] intro f exact CC_exact C hC hsC ho @@ -1478,7 +1477,7 @@ theorem span_sum : Set.range (eval C) = Set.range (Sum.elim theorem square_commutes : SumEval C ho ∘ Sum.inl = - ModuleCat.asHom (πs C o) ∘ eval (π C (ord I · < o)) := by + ModuleCat.ofHom (πs C o) ∘ eval (π C (ord I · < o)) := by ext l dsimp [SumEval] rw [← Products.eval_πs C (Products.prop_of_isGood _ _ l.prop)] @@ -1644,7 +1643,7 @@ theorem maxTail_isGood (l : MaxProducts C ho) rfl have hse := succ_exact C hC hsC ho rw [ShortComplex.moduleCat_exact_iff_range_eq_ker] at hse - dsimp [ModuleCat.asHom] at hse + dsimp [ModuleCat.ofHom] at hse -- Rewrite `this` using exact sequence manipulations to conclude that a term is in the range of -- the linear map `πs`: @@ -1662,7 +1661,7 @@ theorem maxTail_isGood (l : MaxProducts C ho) apply Submodule.add_mem · apply Submodule.finsupp_sum_mem intro q _ - erw [LinearMap.map_smul (fₗ := πs C o) (c := w q) (x := eval (π C (ord I · < o)) q)] + rw [LinearMap.map_smul] apply Submodule.smul_mem apply Submodule.subset_span dsimp only [eval] @@ -1701,9 +1700,9 @@ include hC in theorem linearIndependent_comp_of_eval (h₁ : ⊤ ≤ Submodule.span ℤ (Set.range (eval (π C (ord I · < o))))) : LinearIndependent ℤ (eval (C' C ho)) → - LinearIndependent ℤ (ModuleCat.asHom (Linear_CC' C hsC ho) ∘ SumEval C ho ∘ Sum.inr) := by - dsimp [SumEval, ModuleCat.asHom] - erw [max_eq_eval_unapply C hsC ho] + LinearIndependent ℤ (ModuleCat.ofHom (Linear_CC' C hsC ho) ∘ SumEval C ho ∘ Sum.inr) := by + dsimp [SumEval, ModuleCat.ofHom] + rw [max_eq_eval_unapply C hsC ho] intro h let f := MaxToGood C hC hsC ho h₁ have hf : f.Injective := maxToGood_injective C hC hsC ho h₁ diff --git a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean index 7502f5bebf01b..a42db3835f71f 100644 --- a/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean +++ b/Mathlib/Topology/Category/TopCat/EffectiveEpi.lean @@ -69,7 +69,8 @@ theorem effectiveEpi_iff_isQuotientMap {B X : TopCat.{u}} (π : X ⟶ B) : /- The key to proving that the coequalizer has the quotient topology is `TopCat.coequalizer_isOpen_iff` which characterises the open sets in a coequalizer. -/ · ext U - have : π ≫ i.hom = colimit.ι F WalkingParallelPair.one := by simp [i, ← Iso.eq_comp_inv] + have : π ≫ i.hom = colimit.ι F WalkingParallelPair.one := by + simp [F, i, ← Iso.eq_comp_inv] rw [isOpen_coinduced (f := (homeoOfIso i ∘ π)), coequalizer_isOpen_iff _ U, ← this] rfl diff --git a/Mathlib/Topology/CompactOpen.lean b/Mathlib/Topology/CompactOpen.lean index f3479618c96ad..49f2b425934f9 100644 --- a/Mathlib/Topology/CompactOpen.lean +++ b/Mathlib/Topology/CompactOpen.lean @@ -72,7 +72,7 @@ lemma tendsto_nhds_compactOpen {l : Filter α} {f : α → C(Y, Z)} {g : C(Y, Z) lemma continuous_compactOpen {f : X → C(Y, Z)} : Continuous f ↔ ∀ K, IsCompact K → ∀ U, IsOpen U → IsOpen {x | MapsTo (f x) K U} := - continuous_generateFrom_iff.trans forall_image2_iff + continuous_generateFrom_iff.trans forall_mem_image2 section Functorial @@ -274,7 +274,7 @@ theorem compactOpen_eq_iInf_induced : (ContinuousMap.compactOpen : TopologicalSpace C(X, Y)) = ⨅ (K : Set X) (_ : IsCompact K), .induced (.restrict K) ContinuousMap.compactOpen := by refine le_antisymm (le_iInf₂ fun s _ ↦ compactOpen_le_induced s) ?_ - refine le_generateFrom <| forall_image2_iff.2 fun K (hK : IsCompact K) U hU ↦ ?_ + refine le_generateFrom <| forall_mem_image2.2 fun K (hK : IsCompact K) U hU ↦ ?_ refine TopologicalSpace.le_def.1 (iInf₂_le K hK) _ ?_ convert isOpen_induced (isOpen_setOf_mapsTo (isCompact_iff_isCompact_univ.1 hK) hU) simp [mapsTo_univ_iff, Subtype.forall, MapsTo] diff --git a/Mathlib/Topology/Compactness/Compact.lean b/Mathlib/Topology/Compactness/Compact.lean index 1149080e64cd9..15e1b303bf533 100644 --- a/Mathlib/Topology/Compactness/Compact.lean +++ b/Mathlib/Topology/Compactness/Compact.lean @@ -698,7 +698,7 @@ theorem nhdsSet_prod_le_of_disjoint_cocompact {f : Filter Y} (hs : IsCompact s) _ = 𝓝ˢ (s ×ˢ K) := (hs.nhdsSet_prod_eq hK).symm _ ≤ 𝓝ˢ (s ×ˢ Set.univ) := nhdsSet_mono (prod_mono_right le_top) -theorem prod_nhdsSet_le_of_disjoint_cocompact {f : Filter X} (ht : IsCompact t) +theorem prod_nhdsSet_le_of_disjoint_cocompact {t : Set Y} {f : Filter X} (ht : IsCompact t) (hf : Disjoint f (Filter.cocompact X)) : f ×ˢ 𝓝ˢ t ≤ 𝓝ˢ (Set.univ ×ˢ t) := by obtain ⟨K, hKf, hK⟩ := (disjoint_cocompact_right f).mp hf @@ -709,6 +709,16 @@ theorem prod_nhdsSet_le_of_disjoint_cocompact {f : Filter X} (ht : IsCompact t) _ = 𝓝ˢ (K ×ˢ t) := (hK.nhdsSet_prod_eq ht).symm _ ≤ 𝓝ˢ (Set.univ ×ˢ t) := nhdsSet_mono (prod_mono_left le_top) +theorem nhds_prod_le_of_disjoint_cocompact {f : Filter Y} (x : X) + (hf : Disjoint f (Filter.cocompact Y)) : + 𝓝 x ×ˢ f ≤ 𝓝ˢ ({x} ×ˢ Set.univ) := by + simpa using nhdsSet_prod_le_of_disjoint_cocompact isCompact_singleton hf + +theorem prod_nhds_le_of_disjoint_cocompact {f : Filter X} (y : Y) + (hf : Disjoint f (Filter.cocompact X)) : + f ×ˢ 𝓝 y ≤ 𝓝ˢ (Set.univ ×ˢ {y}) := by + simpa using prod_nhdsSet_le_of_disjoint_cocompact isCompact_singleton hf + /-- If `s` and `t` are compact sets and `n` is an open neighborhood of `s × t`, then there exist open neighborhoods `u ⊇ s` and `v ⊇ t` such that `u × v ⊆ n`. @@ -867,6 +877,16 @@ theorem Filter.comap_cocompact_le {f : X → Y} (hf : Continuous f) : refine ⟨f '' t, ht.image hf, ?_⟩ simpa using t.subset_preimage_image f +/-- If a filter is disjoint from the cocompact filter, so is its image under any continuous +function. -/ +theorem disjoint_map_cocompact {g : X → Y} {f : Filter X} (hg : Continuous g) + (hf : Disjoint f (Filter.cocompact X)) : Disjoint (map g f) (Filter.cocompact Y) := by + rw [← Filter.disjoint_comap_iff_map, disjoint_iff_inf_le] + calc + f ⊓ (comap g (cocompact Y)) + _ ≤ f ⊓ Filter.cocompact X := inf_le_inf_left f (Filter.comap_cocompact_le hg) + _ = ⊥ := disjoint_iff.mp hf + theorem isCompact_range [CompactSpace X] {f : X → Y} (hf : Continuous f) : IsCompact (range f) := by rw [← image_univ]; exact isCompact_univ.image hf diff --git a/Mathlib/Topology/Compactness/DeltaGeneratedSpace.lean b/Mathlib/Topology/Compactness/DeltaGeneratedSpace.lean index c7c9e34c6a6ae..889946c028e5c 100644 --- a/Mathlib/Topology/Compactness/DeltaGeneratedSpace.lean +++ b/Mathlib/Topology/Compactness/DeltaGeneratedSpace.lean @@ -3,7 +3,7 @@ Copyright (c) 2024 Ben Eltschig. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Ben Eltschig -/ -import Mathlib.Analysis.Convex.Normed +import Mathlib.Analysis.LocallyConvex.WithSeminorms /-! # Delta-generated topological spaces diff --git a/Mathlib/Topology/Connected/PathConnected.lean b/Mathlib/Topology/Connected/PathConnected.lean index c5d94601f96f7..47f59cf4a2bd6 100644 --- a/Mathlib/Topology/Connected/PathConnected.lean +++ b/Mathlib/Topology/Connected/PathConnected.lean @@ -544,7 +544,6 @@ def truncate {X : Type*} [TopologicalSpace X] {a b : X} (γ : Path a b) (t₀ t γ.continuous_extend.comp ((continuous_subtype_val.max continuous_const).min continuous_const) source' := by simp only [min_def, max_def'] - norm_cast split_ifs with h₁ h₂ h₃ h₄ · simp [γ.extend_of_le_zero h₁] · congr @@ -554,7 +553,6 @@ def truncate {X : Type*} [TopologicalSpace X] {a b : X} (γ : Path a b) (t₀ t all_goals rfl target' := by simp only [min_def, max_def'] - norm_cast split_ifs with h₁ h₂ h₃ · simp [γ.extend_of_one_le h₂] · rfl @@ -1185,6 +1183,11 @@ protected theorem IsClosed.pathComponent (x : X) : IsClosed (pathComponent x) := protected theorem IsClopen.pathComponent (x : X) : IsClopen (pathComponent x) := ⟨.pathComponent x, .pathComponent x⟩ +lemma pathComponentIn_mem_nhds (hF : F ∈ 𝓝 x) : pathComponentIn x F ∈ 𝓝 x := by + let ⟨u, huF, hu, hxu⟩ := mem_nhds_iff.mp hF + exact mem_nhds_iff.mpr ⟨pathComponentIn x u, pathComponentIn_mono huF, + hu.pathComponentIn x, mem_pathComponentIn_self hxu⟩ + theorem pathConnectedSpace_iff_connectedSpace : PathConnectedSpace X ↔ ConnectedSpace X := by refine ⟨fun _ ↦ inferInstance, fun h ↦ ⟨inferInstance, fun x y ↦ ?_⟩⟩ rw [← mem_pathComponent_iff, (IsClopen.pathComponent _).eq_univ] <;> simp diff --git a/Mathlib/Topology/Constructions.lean b/Mathlib/Topology/Constructions.lean index 280967dfdc29d..97a7797155a00 100644 --- a/Mathlib/Topology/Constructions.lean +++ b/Mathlib/Topology/Constructions.lean @@ -477,11 +477,9 @@ theorem IsOpen.prod {s : Set X} {t : Set Y} (hs : IsOpen s) (ht : IsOpen t) : Is -- Porting note (https://github.com/leanprover-community/mathlib4/issues/11215): TODO: Lean fails to find `t₁` and `t₂` by unification theorem nhds_prod_eq {x : X} {y : Y} : 𝓝 (x, y) = 𝓝 x ×ˢ 𝓝 y := by - dsimp only [SProd.sprod] - rw [Filter.prod, instTopologicalSpaceProd, nhds_inf (t₁ := TopologicalSpace.induced Prod.fst _) + rw [prod_eq_inf, instTopologicalSpaceProd, nhds_inf (t₁ := TopologicalSpace.induced Prod.fst _) (t₂ := TopologicalSpace.induced Prod.snd _), nhds_induced, nhds_induced] --- Porting note: moved from `Topology.ContinuousOn` theorem nhdsWithin_prod_eq (x : X) (y : Y) (s : Set X) (t : Set Y) : 𝓝[s ×ˢ t] (x, y) = 𝓝[s] x ×ˢ 𝓝[t] y := by simp only [nhdsWithin, nhds_prod_eq, ← prod_inf_prod, prod_principal_principal] @@ -504,7 +502,6 @@ theorem mem_nhdsWithin_prod_iff {x : X} {y : Y} {s : Set (X × Y)} {tx : Set X} s ∈ 𝓝[tx ×ˢ ty] (x, y) ↔ ∃ u ∈ 𝓝[tx] x, ∃ v ∈ 𝓝[ty] y, u ×ˢ v ⊆ s := by rw [nhdsWithin_prod_eq, mem_prod_iff] --- Porting note: moved up theorem Filter.HasBasis.prod_nhds {ιX ιY : Type*} {px : ιX → Prop} {py : ιY → Prop} {sx : ιX → Set X} {sy : ιY → Set Y} {x : X} {y : Y} (hx : (𝓝 x).HasBasis px sx) (hy : (𝓝 y).HasBasis py sy) : @@ -512,7 +509,6 @@ theorem Filter.HasBasis.prod_nhds {ιX ιY : Type*} {px : ιX → Prop} {py : ι rw [nhds_prod_eq] exact hx.prod hy --- Porting note: moved up theorem Filter.HasBasis.prod_nhds' {ιX ιY : Type*} {pX : ιX → Prop} {pY : ιY → Prop} {sx : ιX → Set X} {sy : ιY → Set Y} {p : X × Y} (hx : (𝓝 p.1).HasBasis pX sx) (hy : (𝓝 p.2).HasBasis pY sy) : diff --git a/Mathlib/Topology/ContinuousMap/Algebra.lean b/Mathlib/Topology/ContinuousMap/Algebra.lean index 42a37d593e9a0..58c98d954d09d 100644 --- a/Mathlib/Topology/ContinuousMap/Algebra.lean +++ b/Mathlib/Topology/ContinuousMap/Algebra.lean @@ -617,6 +617,13 @@ def coeFnLinearMap : C(α, M) →ₗ[R] α → M := { (coeFnAddMonoidHom : C(α, M) →+ _) with map_smul' := coe_smul } +/-- Evaluation at a point, as a continuous linear map. -/ +@[simps apply] +def evalCLM (x : α) : C(α, M) →L[R] M where + toFun f := f x + map_add' _ _ := add_apply _ _ x + map_smul' _ _ := smul_apply _ _ x + end ContinuousMap end ModuleStructure @@ -760,8 +767,8 @@ theorem Subalgebra.SeparatesPoints.strongly {s : Subalgebra 𝕜 C(α, 𝕜)} (h let f' : s := ((b - a) * (f x - f y)⁻¹) • (algebraMap _ s (f x) - (⟨f, hf⟩ : s)) + algebraMap _ s a refine ⟨f', f'.prop, ?_, ?_⟩ - · simp [f'] - · simp [f', inv_mul_cancel_right₀ hxy] + · simp [a, b, f'] + · simp [a, b, f', inv_mul_cancel_right₀ hxy] end ContinuousMap diff --git a/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean b/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean index 63492cdc8f0e7..ab3605b44b21f 100644 --- a/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean +++ b/Mathlib/Topology/ContinuousMap/Bounded/Basic.lean @@ -4,11 +4,12 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel, Mario Carneiro, Yury Kudryashov, Heather Macbeth -/ import Mathlib.Algebra.Module.MinimalAxioms -import Mathlib.Topology.ContinuousMap.Algebra import Mathlib.Analysis.Normed.Order.Lattice import Mathlib.Analysis.NormedSpace.OperatorNorm.Basic -import Mathlib.Topology.Bornology.BoundedOperation import Mathlib.Tactic.Monotonicity +import Mathlib.Topology.Algebra.Indicator +import Mathlib.Topology.Bornology.BoundedOperation +import Mathlib.Topology.ContinuousMap.Algebra /-! # Bounded continuous functions @@ -1088,14 +1089,12 @@ instance instModule : Module 𝕜 (α →ᵇ β) := variable (𝕜) /-- The evaluation at a point, as a continuous linear map from `α →ᵇ β` to `β`. -/ +@[simps] def evalCLM (x : α) : (α →ᵇ β) →L[𝕜] β where toFun f := f x map_add' _ _ := add_apply _ _ map_smul' _ _ := smul_apply _ _ _ -@[simp] -theorem evalCLM_apply (x : α) (f : α →ᵇ β) : evalCLM 𝕜 x f = f x := rfl - variable (α β) /-- The linear map forgetting that a bounded continuous function is bounded. -/ diff --git a/Mathlib/Topology/ContinuousMap/Compact.lean b/Mathlib/Topology/ContinuousMap/Compact.lean index e6cb2f048e863..1e69d46a45e39 100644 --- a/Mathlib/Topology/ContinuousMap/Compact.lean +++ b/Mathlib/Topology/ContinuousMap/Compact.lean @@ -301,14 +301,6 @@ def linearIsometryBoundedOfCompact : C(α, E) ≃ₗᵢ[𝕜] α →ᵇ E := norm_cast norm_map' := fun _ => rfl } -variable {α E} - --- to match `BoundedContinuousFunction.evalCLM` -/-- The evaluation at a point, as a continuous linear map from `C(α, 𝕜)` to `𝕜`. -/ -def evalCLM (x : α) : C(α, E) →L[𝕜] E := - (BoundedContinuousFunction.evalCLM 𝕜 x).comp - (linearIsometryBoundedOfCompact α E 𝕜).toLinearIsometry.toContinuousLinearMap - end -- this lemma and the next are the analogues of those autogenerated by `@[simps]` for diff --git a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean index cb59956edbce0..eb5348c9f448c 100644 --- a/Mathlib/Topology/ContinuousMap/CompactlySupported.lean +++ b/Mathlib/Topology/ContinuousMap/CompactlySupported.lean @@ -3,9 +3,9 @@ Copyright (c) 2024 Yoh Tanimoto. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Yoh Tanimoto -/ +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.ContinuousMap.CocompactMap import Mathlib.Topology.ContinuousMap.ZeroAtInfty -import Mathlib.Topology.Support /-! # Compactly supported continuous functions diff --git a/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean index e69cf73093b84..d354b286c82fb 100644 --- a/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean +++ b/Mathlib/Topology/ContinuousMap/ContinuousMapZero.lean @@ -230,13 +230,13 @@ def toContinuousMapCLM (M : Type*) [Semiring M] [Module M R] [ContinuousConstSMu map_smul' _ _ := rfl /-- The evaluation at a point, as a continuous linear map from `C(X, R)₀` to `R`. -/ -def evalCLM (𝕜 : Type*) {R : Type*} [CompactSpace X] [NormedField 𝕜] [NormedCommRing R] - [NormedSpace 𝕜 R] (x : X) : C(X, R)₀ →L[𝕜] R := - (ContinuousMap.evalCLM 𝕜 x).comp (toContinuousMapCLM 𝕜 : C(X, R)₀ →L[𝕜] C(X, R)) +def evalCLM (𝕜 : Type*) [Semiring 𝕜] [Module 𝕜 R] [ContinuousConstSMul 𝕜 R] (x : X) : + C(X, R)₀ →L[𝕜] R := + (ContinuousMap.evalCLM 𝕜 x).comp (toContinuousMapCLM 𝕜) @[simp] -lemma evalCLM_apply {𝕜 : Type*} {R : Type*} [CompactSpace X] [NormedField 𝕜] [NormedCommRing R] - [NormedSpace 𝕜 R] (x : X) (f : C(X, R)₀) : evalCLM 𝕜 x f = f x := rfl +lemma evalCLM_apply {𝕜 : Type*} [Semiring 𝕜] [Module 𝕜 R] [ContinuousConstSMul 𝕜 R] + (x : X) (f : C(X, R)₀) : evalCLM 𝕜 x f = f x := rfl /-- Coercion to a function as an `AddMonoidHom`. Similar to `ContinuousMap.coeFnAddMonoidHom`. -/ def coeFnAddMonoidHom : C(X, R)₀ →+ X → R where diff --git a/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean index b3ec116499bc4..e62e6489c8c9e 100644 --- a/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean +++ b/Mathlib/Topology/ContinuousMap/StoneWeierstrass.lean @@ -213,10 +213,10 @@ theorem sublattice_closure_eq_top (L : Set C(X, ℝ)) (nA : L.Nonempty) have lt_h : ∀ x z, f z - ε < (h x : X → ℝ) z := by intro x z obtain ⟨y, ym, zm⟩ := Set.exists_set_mem_of_union_eq_top _ _ (ys_w x) z - dsimp + dsimp [h] simp only [Subtype.coe_mk, coe_sup', Finset.sup'_apply, Finset.lt_sup'_iff] exact ⟨y, ym, zm⟩ - have h_eq : ∀ x, (h x : X → ℝ) x = f x := by intro x; simp [w₁] + have h_eq : ∀ x, (h x : X → ℝ) x = f x := by intro x; simp [h, w₁] -- For each `x`, we define `W x` to be `{z | h x z < f z + ε}`, let W : X → Set X := fun x => {z | (h x : X → ℝ) z < f z + ε} -- This is still a neighbourhood of `x`. @@ -247,10 +247,10 @@ theorem sublattice_closure_eq_top (L : Set C(X, ℝ)) (nA : L.Nonempty) intros; simp only [← Metric.mem_ball, Real.ball_eq_Ioo, Set.mem_Ioo, and_comm]] fconstructor · dsimp - simp only [Finset.inf'_lt_iff, ContinuousMap.inf'_apply] + simp only [k, Finset.inf'_lt_iff, ContinuousMap.inf'_apply] exact Set.exists_set_mem_of_union_eq_top _ _ xs_w z · dsimp - simp only [Finset.lt_inf'_iff, ContinuousMap.inf'_apply] + simp only [k, Finset.lt_inf'_iff, ContinuousMap.inf'_apply] rintro x - apply lt_h diff --git a/Mathlib/Topology/ContinuousOn.lean b/Mathlib/Topology/ContinuousOn.lean index 3e1d97b1dedd0..56c76196a7d53 100644 --- a/Mathlib/Topology/ContinuousOn.lean +++ b/Mathlib/Topology/ContinuousOn.lean @@ -3,7 +3,6 @@ Copyright (c) 2019 Reid Barton. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Algebra.Group.Indicator import Mathlib.Topology.Constructions /-! @@ -1403,21 +1402,6 @@ theorem Continuous.piecewise [∀ a, Decidable (a ∈ s)] Continuous (piecewise s f g) := hf.if hs hg -section Indicator -variable [One β] - -@[to_additive] -lemma continuous_mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf : ContinuousOn f (closure s)) : - Continuous (mulIndicator s f) := by - classical exact continuous_piecewise hs hf continuousOn_const - -@[to_additive] -protected lemma Continuous.mulIndicator (hs : ∀ a ∈ frontier s, f a = 1) (hf : Continuous f) : - Continuous (mulIndicator s f) := by - classical exact hf.piecewise hs continuous_const - -end Indicator - theorem IsOpen.ite' (hs : IsOpen s) (hs' : IsOpen s') (ht : ∀ x ∈ frontier t, x ∈ s ↔ x ∈ s') : IsOpen (t.ite s s') := by classical diff --git a/Mathlib/Topology/Defs/Basic.lean b/Mathlib/Topology/Defs/Basic.lean index e7526dd6e9024..ba372a4470a09 100644 --- a/Mathlib/Topology/Defs/Basic.lean +++ b/Mathlib/Topology/Defs/Basic.lean @@ -100,7 +100,7 @@ def IsClopen (s : Set X) : Prop := /-- A set is locally closed if it is the intersection of some open set and some closed set. -Also see `isLocallyClosed_tfae` and other lemmas in `Mathlib/Topology/LocallyClosed`. +Also see `isLocallyClosed_tfae` and other lemmas in `Mathlib/Topology/LocallyClosed.lean`. -/ def IsLocallyClosed (s : Set X) : Prop := ∃ (U Z : Set X), IsOpen U ∧ IsClosed Z ∧ s = U ∩ Z diff --git a/Mathlib/Topology/EMetricSpace/BoundedVariation.lean b/Mathlib/Topology/EMetricSpace/BoundedVariation.lean new file mode 100644 index 0000000000000..a8258f7c11588 --- /dev/null +++ b/Mathlib/Topology/EMetricSpace/BoundedVariation.lean @@ -0,0 +1,777 @@ +/- +Copyright (c) 2022 Sébastien Gouëzel. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Sébastien Gouëzel +-/ +import Mathlib.Order.Interval.Set.ProjIcc +import Mathlib.Topology.Semicontinuous +import Mathlib.Topology.UniformSpace.UniformConvergenceTopology + +/-! +# Functions of bounded variation + +We study functions of bounded variation. In particular, we show that a bounded variation function +is a difference of monotone functions, and differentiable almost everywhere. This implies that +Lipschitz functions from the real line into finite-dimensional vector space are also differentiable +almost everywhere. + +## Main definitions and results + +* `eVariationOn f s` is the total variation of the function `f` on the set `s`, in `ℝ≥0∞`. +* `BoundedVariationOn f s` registers that the variation of `f` on `s` is finite. +* `LocallyBoundedVariationOn f s` registers that `f` has finite variation on any compact + subinterval of `s`. +* `variationOnFromTo f s a b` is the signed variation of `f` on `s ∩ Icc a b`, converted to `ℝ`. + +* `eVariationOn.Icc_add_Icc` states that the variation of `f` on `[a, c]` is the sum of its + variations on `[a, b]` and `[b, c]`. +* `LocallyBoundedVariationOn.exists_monotoneOn_sub_monotoneOn` proves that a function + with locally bounded variation is the difference of two monotone functions. +* `LipschitzWith.locallyBoundedVariationOn` shows that a Lipschitz function has locally + bounded variation. + +We also give several variations around these results. + +## Implementation + +We define the variation as an extended nonnegative real, to allow for infinite variation. This makes +it possible to use the complete linear order structure of `ℝ≥0∞`. The proofs would be much +more tedious with an `ℝ`-valued or `ℝ≥0`-valued variation, since one would always need to check +that the sets one uses are nonempty and bounded above as these are only conditionally complete. +-/ + + +open scoped NNReal ENNReal Topology UniformConvergence +open Set Filter + +-- Porting note: sectioned variables because a `wlog` was broken due to extra variables in context +variable {α : Type*} [LinearOrder α] {E : Type*} [PseudoEMetricSpace E] + +/-- The (extended real valued) variation of a function `f` on a set `s` inside a linear order is +the supremum of the sum of `edist (f (u (i+1))) (f (u i))` over all finite increasing +sequences `u` in `s`. -/ +noncomputable def eVariationOn (f : α → E) (s : Set α) : ℝ≥0∞ := + ⨆ p : ℕ × { u : ℕ → α // Monotone u ∧ ∀ i, u i ∈ s }, + ∑ i ∈ Finset.range p.1, edist (f (p.2.1 (i + 1))) (f (p.2.1 i)) + +/-- A function has bounded variation on a set `s` if its total variation there is finite. -/ +def BoundedVariationOn (f : α → E) (s : Set α) := + eVariationOn f s ≠ ∞ + +/-- A function has locally bounded variation on a set `s` if, given any interval `[a, b]` with +endpoints in `s`, then the function has finite variation on `s ∩ [a, b]`. -/ +def LocallyBoundedVariationOn (f : α → E) (s : Set α) := + ∀ a b, a ∈ s → b ∈ s → BoundedVariationOn f (s ∩ Icc a b) + +/-! ## Basic computations of variation -/ + +namespace eVariationOn + +theorem nonempty_monotone_mem {s : Set α} (hs : s.Nonempty) : + Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ s } := by + obtain ⟨x, hx⟩ := hs + exact ⟨⟨fun _ => x, fun i j _ => le_rfl, fun _ => hx⟩⟩ + +theorem eq_of_edist_zero_on {f f' : α → E} {s : Set α} (h : ∀ ⦃x⦄, x ∈ s → edist (f x) (f' x) = 0) : + eVariationOn f s = eVariationOn f' s := by + dsimp only [eVariationOn] + congr 1 with p : 1 + congr 1 with i : 1 + rw [edist_congr_right (h <| p.snd.prop.2 (i + 1)), edist_congr_left (h <| p.snd.prop.2 i)] + +theorem eq_of_eqOn {f f' : α → E} {s : Set α} (h : EqOn f f' s) : + eVariationOn f s = eVariationOn f' s := + eq_of_edist_zero_on fun x xs => by rw [h xs, edist_self] + +theorem sum_le (f : α → E) {s : Set α} (n : ℕ) {u : ℕ → α} (hu : Monotone u) (us : ∀ i, u i ∈ s) : + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := + le_iSup_of_le ⟨n, u, hu, us⟩ le_rfl + +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 ∈ Finset.Ico m n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := by + 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) + calc + ∑ i ∈ Finset.Ico m n, edist (f (u (i + 1))) (f (u i)) + = ∑ i ∈ Finset.Ico m n, edist (f (v (i + 1))) (f (v i)) := + Finset.sum_congr rfl fun i hi ↦ by + rw [Finset.mem_Ico] at hi + simp only [v, π, projIcc_of_mem hmn ⟨hi.1, hi.2.le⟩, + projIcc_of_mem hmn ⟨hi.1.trans i.le_succ, hi.2⟩] + _ ≤ ∑ i ∈ Finset.range n, edist (f (v (i + 1))) (f (v i)) := + Finset.sum_mono_set _ (Nat.Iio_eq_range ▸ Finset.Ico_subset_Iio_self) + _ ≤ eVariationOn f s := + sum_le _ _ (fun i j h ↦ hu (π i).2 (π j).2 (monotone_projIcc hmn h)) fun i ↦ us _ (π i).2 + +theorem sum_le_of_monotoneOn_Iic (f : α → E) {s : Set α} {n : ℕ} {u : ℕ → α} + (hu : MonotoneOn u (Iic n)) (us : ∀ i ≤ n, u i ∈ s) : + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ eVariationOn f s := by + simpa using sum_le_of_monotoneOn_Icc f (m := 0) (hu.mono Icc_subset_Iic_self) fun i hi ↦ us i hi.2 + +theorem mono (f : α → E) {s t : Set α} (hst : t ⊆ s) : eVariationOn f t ≤ eVariationOn f s := by + apply iSup_le _ + rintro ⟨n, ⟨u, hu, ut⟩⟩ + exact sum_le f n hu fun i => hst (ut i) + +theorem _root_.BoundedVariationOn.mono {f : α → E} {s : Set α} (h : BoundedVariationOn f s) + {t : Set α} (ht : t ⊆ s) : BoundedVariationOn f t := + ne_top_of_le_ne_top h (eVariationOn.mono f ht) + +theorem _root_.BoundedVariationOn.locallyBoundedVariationOn {f : α → E} {s : Set α} + (h : BoundedVariationOn f s) : LocallyBoundedVariationOn f s := fun _ _ _ _ => + h.mono inter_subset_left + +theorem edist_le (f : α → E) {s : Set α} {x y : α} (hx : x ∈ s) (hy : y ∈ s) : + edist (f x) (f y) ≤ eVariationOn f s := by + wlog hxy : y ≤ x generalizing x y + · rw [edist_comm] + exact this hy hx (le_of_not_le hxy) + let u : ℕ → α := fun n => if n = 0 then y else x + have hu : Monotone u := monotone_nat_of_le_succ fun + | 0 => hxy + | (_ + 1) => le_rfl + have us : ∀ i, u i ∈ s := fun + | 0 => hy + | (_ + 1) => hx + simpa only [Finset.sum_range_one] using sum_le f 1 hu us + +theorem eq_zero_iff (f : α → E) {s : Set α} : + eVariationOn f s = 0 ↔ ∀ x ∈ s, ∀ y ∈ s, edist (f x) (f y) = 0 := by + constructor + · rintro h x xs y ys + rw [← le_zero_iff, ← h] + exact edist_le f xs ys + · rintro h + dsimp only [eVariationOn] + rw [ENNReal.iSup_eq_zero] + rintro ⟨n, u, um, us⟩ + exact Finset.sum_eq_zero fun i _ => h _ (us i.succ) _ (us i) + +theorem constant_on {f : α → E} {s : Set α} (hf : (f '' s).Subsingleton) : + eVariationOn f s = 0 := by + rw [eq_zero_iff] + rintro x xs y ys + rw [hf ⟨x, xs, rfl⟩ ⟨y, ys, rfl⟩, edist_self] + +@[simp] +protected theorem subsingleton (f : α → E) {s : Set α} (hs : s.Subsingleton) : + eVariationOn f s = 0 := + constant_on (hs.image f) + +theorem lowerSemicontinuous_aux {ι : Type*} {F : ι → α → E} {p : Filter ι} {f : α → E} {s : Set α} + (Ffs : ∀ x ∈ s, Tendsto (fun i => F i x) p (𝓝 (f x))) {v : ℝ≥0∞} (hv : v < eVariationOn f s) : + ∀ᶠ n : ι in p, v < eVariationOn (F n) s := by + obtain ⟨⟨n, ⟨u, um, us⟩⟩, hlt⟩ : + ∃ p : ℕ × { u : ℕ → α // Monotone u ∧ ∀ i, u i ∈ s }, + v < ∑ i ∈ Finset.range p.1, edist (f ((p.2 : ℕ → α) (i + 1))) (f ((p.2 : ℕ → α) i)) := + lt_iSup_iff.mp hv + have : Tendsto (fun j => ∑ i ∈ Finset.range n, edist (F j (u (i + 1))) (F j (u i))) p + (𝓝 (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i)))) := by + apply tendsto_finset_sum + exact fun i _ => Tendsto.edist (Ffs (u i.succ) (us i.succ)) (Ffs (u i) (us i)) + exact (this.eventually_const_lt hlt).mono fun i h => h.trans_le (sum_le (F i) n um us) + +/-- The map `(eVariationOn · s)` is lower semicontinuous for pointwise convergence *on `s`*. +Pointwise convergence on `s` is encoded here as uniform convergence on the family consisting of the +singletons of elements of `s`. +-/ +protected theorem lowerSemicontinuous (s : Set α) : + LowerSemicontinuous fun f : α →ᵤ[s.image singleton] E => eVariationOn f s := fun f ↦ by + apply @lowerSemicontinuous_aux _ _ _ _ (UniformOnFun α E (s.image singleton)) id (𝓝 f) f s _ + simpa only [UniformOnFun.tendsto_iff_tendstoUniformlyOn, mem_image, forall_exists_index, and_imp, + forall_apply_eq_imp_iff₂, tendstoUniformlyOn_singleton_iff_tendsto] using @tendsto_id _ (𝓝 f) + +/-- The map `(eVariationOn · s)` is lower semicontinuous for uniform convergence on `s`. -/ +theorem lowerSemicontinuous_uniformOn (s : Set α) : + LowerSemicontinuous fun f : α →ᵤ[{s}] E => eVariationOn f s := fun f ↦ by + apply @lowerSemicontinuous_aux _ _ _ _ (UniformOnFun α E {s}) id (𝓝 f) f s _ + have := @tendsto_id _ (𝓝 f) + rw [UniformOnFun.tendsto_iff_tendstoUniformlyOn] at this + simp_rw [← tendstoUniformlyOn_singleton_iff_tendsto] + exact fun x xs => (this s rfl).mono (singleton_subset_iff.mpr xs) + +theorem _root_.BoundedVariationOn.dist_le {E : Type*} [PseudoMetricSpace E] {f : α → E} + {s : Set α} (h : BoundedVariationOn f s) {x y : α} (hx : x ∈ s) (hy : y ∈ s) : + dist (f x) (f y) ≤ (eVariationOn f s).toReal := by + rw [← ENNReal.ofReal_le_ofReal_iff ENNReal.toReal_nonneg, ENNReal.ofReal_toReal h, ← edist_dist] + exact edist_le f hx hy + +theorem _root_.BoundedVariationOn.sub_le {f : α → ℝ} {s : Set α} (h : BoundedVariationOn f s) + {x y : α} (hx : x ∈ s) (hy : y ∈ s) : f x - f y ≤ (eVariationOn f s).toReal := by + apply (le_abs_self _).trans + rw [← Real.dist_eq] + exact h.dist_le hx hy + +/-- Consider a monotone function `u` parameterizing some points of a set `s`. Given `x ∈ s`, then +one can find another monotone function `v` parameterizing the same points as `u`, with `x` added. +In particular, the variation of a function along `u` is bounded by its variation along `v`. -/ +theorem add_point (f : α → E) {s : Set α} {x : α} (hx : x ∈ s) (u : ℕ → α) (hu : Monotone u) + (us : ∀ i, u i ∈ s) (n : ℕ) : + ∃ (v : ℕ → α) (m : ℕ), Monotone v ∧ (∀ i, v i ∈ s) ∧ x ∈ v '' Iio m ∧ + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ + ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := by + rcases le_or_lt (u n) x with (h | h) + · let v i := if i ≤ n then u i else x + have vs : ∀ i, v i ∈ s := fun i ↦ by + simp only [v] + split_ifs + · exact us i + · exact hx + have hv : Monotone v := by + refine monotone_nat_of_le_succ fun i => ?_ + simp only [v] + rcases lt_trichotomy i n with (hi | rfl | hi) + · have : i + 1 ≤ n := Nat.succ_le_of_lt hi + simp only [hi.le, this, if_true] + exact hu (Nat.le_succ i) + · simp only [le_refl, if_true, add_le_iff_nonpos_right, Nat.le_zero, Nat.one_ne_zero, + if_false, h] + · have A : ¬i ≤ n := hi.not_le + have B : ¬i + 1 ≤ n := fun h => A (i.le_succ.trans h) + simp only [A, B, if_false, le_rfl] + refine ⟨v, n + 2, hv, vs, (mem_image _ _ _).2 ⟨n + 1, ?_, ?_⟩, ?_⟩ + · rw [mem_Iio]; exact Nat.lt_succ_self (n + 1) + · have : ¬n + 1 ≤ n := Nat.not_succ_le_self n + simp only [v, this, ite_eq_right_iff, IsEmpty.forall_iff] + · calc + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = + ∑ i ∈ Finset.range n, edist (f (v (i + 1))) (f (v i)) := by + apply Finset.sum_congr rfl fun i hi => ?_ + simp only [Finset.mem_range] at hi + have : i + 1 ≤ n := Nat.succ_le_of_lt hi + simp only [v, hi.le, this, if_true] + _ ≤ ∑ j ∈ Finset.range (n + 2), edist (f (v (j + 1))) (f (v j)) := + Finset.sum_le_sum_of_subset (Finset.range_mono (Nat.le_add_right n 2)) + have exists_N : ∃ N, N ≤ n ∧ x < u N := ⟨n, le_rfl, h⟩ + let N := Nat.find exists_N + have hN : N ≤ n ∧ x < u N := Nat.find_spec exists_N + let w : ℕ → α := fun i => if i < N then u i else if i = N then x else u (i - 1) + have ws : ∀ i, w i ∈ s := by + dsimp only [w] + intro i + split_ifs + exacts [us _, hx, us _] + have hw : Monotone w := by + apply monotone_nat_of_le_succ fun i => ?_ + dsimp only [w] + rcases lt_trichotomy (i + 1) N with (hi | hi | hi) + · have : i < N := Nat.lt_of_le_of_lt (Nat.le_succ i) hi + simp only [hi, this, if_true] + exact hu (Nat.le_succ _) + · have A : i < N := hi ▸ i.lt_succ_self + have B : ¬i + 1 < N := by rw [← hi]; exact fun h => h.ne rfl + rw [if_pos A, if_neg B, if_pos hi] + have T := Nat.find_min exists_N A + push_neg at T + exact T (A.le.trans hN.1) + · have A : ¬i < N := (Nat.lt_succ_iff.mp hi).not_lt + have B : ¬i + 1 < N := hi.not_lt + have C : ¬i + 1 = N := hi.ne.symm + have D : i + 1 - 1 = i := Nat.pred_succ i + rw [if_neg A, if_neg B, if_neg C, D] + split_ifs + · exact hN.2.le.trans (hu (le_of_not_lt A)) + · exact hu (Nat.pred_le _) + refine ⟨w, n + 1, hw, ws, (mem_image _ _ _).2 ⟨N, hN.1.trans_lt (Nat.lt_succ_self n), ?_⟩, ?_⟩ + · dsimp only [w]; rw [if_neg (lt_irrefl N), if_pos rfl] + rcases eq_or_lt_of_le (zero_le N) with (Npos | Npos) + · calc + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = + ∑ i ∈ Finset.range n, edist (f (w (1 + i + 1))) (f (w (1 + i))) := by + apply Finset.sum_congr rfl fun i _hi => ?_ + dsimp only [w] + simp only [← Npos, Nat.not_lt_zero, Nat.add_succ_sub_one, add_zero, if_false, + add_eq_zero, Nat.one_ne_zero, false_and, Nat.succ_add_sub_one, zero_add] + rw [add_comm 1 i] + _ = ∑ i ∈ Finset.Ico 1 (n + 1), edist (f (w (i + 1))) (f (w i)) := by + rw [Finset.range_eq_Ico] + exact Finset.sum_Ico_add (fun i => edist (f (w (i + 1))) (f (w i))) 0 n 1 + _ ≤ ∑ j ∈ Finset.range (n + 1), edist (f (w (j + 1))) (f (w j)) := by + apply Finset.sum_le_sum_of_subset _ + rw [Finset.range_eq_Ico] + exact Finset.Ico_subset_Ico zero_le_one le_rfl + · calc + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = + ((∑ i ∈ Finset.Ico 0 (N - 1), edist (f (u (i + 1))) (f (u i))) + + ∑ i ∈ Finset.Ico (N - 1) N, edist (f (u (i + 1))) (f (u i))) + + ∑ i ∈ Finset.Ico N n, edist (f (u (i + 1))) (f (u i)) := by + rw [Finset.sum_Ico_consecutive, Finset.sum_Ico_consecutive, Finset.range_eq_Ico] + · exact zero_le _ + · exact hN.1 + · exact zero_le _ + · exact Nat.pred_le _ + _ = (∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + + edist (f (u N)) (f (u (N - 1))) + + ∑ i ∈ Finset.Ico N n, edist (f (w (1 + i + 1))) (f (w (1 + i))) := by + congr 1 + · congr 1 + · apply Finset.sum_congr rfl fun i hi => ?_ + simp only [Finset.mem_Ico, zero_le', true_and] at hi + dsimp only [w] + have A : i + 1 < N := Nat.lt_pred_iff.1 hi + have B : i < N := Nat.lt_of_succ_lt A + rw [if_pos A, if_pos B] + · have A : N - 1 + 1 = N := Nat.succ_pred_eq_of_pos Npos + have : Finset.Ico (N - 1) N = {N - 1} := by rw [← Nat.Ico_succ_singleton, A] + simp only [this, A, Finset.sum_singleton] + · apply Finset.sum_congr rfl fun i hi => ?_ + rw [Finset.mem_Ico] at hi + dsimp only [w] + have A : ¬1 + i + 1 < N := by omega + have B : ¬1 + i + 1 = N := by omega + have C : ¬1 + i < N := by omega + have D : ¬1 + i = N := by omega + rw [if_neg A, if_neg B, if_neg C, if_neg D] + congr 3 <;> · rw [add_comm, Nat.sub_one]; apply Nat.pred_succ + _ = (∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + + edist (f (w (N + 1))) (f (w (N - 1))) + + ∑ i ∈ Finset.Ico (N + 1) (n + 1), edist (f (w (i + 1))) (f (w i)) := by + congr 1 + · congr 1 + · dsimp only [w] + have A : ¬N + 1 < N := Nat.not_succ_lt_self + have B : N - 1 < N := Nat.pred_lt Npos.ne' + simp only [A, not_and, not_lt, Nat.succ_ne_self, Nat.add_succ_sub_one, add_zero, + if_false, B, if_true] + · exact Finset.sum_Ico_add (fun i => edist (f (w (i + 1))) (f (w i))) N n 1 + _ ≤ ((∑ i ∈ Finset.Ico 0 (N - 1), edist (f (w (i + 1))) (f (w i))) + + ∑ i ∈ Finset.Ico (N - 1) (N + 1), edist (f (w (i + 1))) (f (w i))) + + ∑ i ∈ Finset.Ico (N + 1) (n + 1), edist (f (w (i + 1))) (f (w i)) := by + refine add_le_add (add_le_add le_rfl ?_) le_rfl + have A : N - 1 + 1 = N := Nat.succ_pred_eq_of_pos Npos + have B : N - 1 + 1 < N + 1 := A.symm ▸ N.lt_succ_self + have C : N - 1 < N + 1 := lt_of_le_of_lt N.pred_le N.lt_succ_self + rw [Finset.sum_eq_sum_Ico_succ_bot C, Finset.sum_eq_sum_Ico_succ_bot B, A, Finset.Ico_self, + Finset.sum_empty, add_zero, add_comm (edist _ _)] + exact edist_triangle _ _ _ + _ = ∑ j ∈ Finset.range (n + 1), edist (f (w (j + 1))) (f (w j)) := by + rw [Finset.sum_Ico_consecutive, Finset.sum_Ico_consecutive, Finset.range_eq_Ico] + · exact zero_le _ + · exact Nat.succ_le_succ hN.left + · exact zero_le _ + · exact N.pred_le.trans N.le_succ + +/-- The variation of a function on the union of two sets `s` and `t`, with `s` to the left of `t`, +bounds the sum of the variations along `s` and `t`. -/ +theorem add_le_union (f : α → E) {s t : Set α} (h : ∀ x ∈ s, ∀ y ∈ t, x ≤ y) : + eVariationOn f s + eVariationOn f t ≤ eVariationOn f (s ∪ t) := by + by_cases hs : s = ∅ + · simp [hs] + have : Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ s } := + nonempty_monotone_mem (nonempty_iff_ne_empty.2 hs) + by_cases ht : t = ∅ + · simp [ht] + have : Nonempty { u // Monotone u ∧ ∀ i : ℕ, u i ∈ t } := + nonempty_monotone_mem (nonempty_iff_ne_empty.2 ht) + refine ENNReal.iSup_add_iSup_le ?_ + /- We start from two sequences `u` and `v` along `s` and `t` respectively, and we build a new + sequence `w` along `s ∪ t` by juxtaposing them. Its variation is larger than the sum of the + variations. -/ + rintro ⟨n, ⟨u, hu, us⟩⟩ ⟨m, ⟨v, hv, vt⟩⟩ + let w i := if i ≤ n then u i else v (i - (n + 1)) + have wst : ∀ i, w i ∈ s ∪ t := by + intro i + by_cases hi : i ≤ n + · simp [w, hi, us] + · simp [w, hi, vt] + have hw : Monotone w := by + intro i j hij + dsimp only [w] + split_ifs with h_1 h_2 h_2 + · exact hu hij + · apply h _ (us _) _ (vt _) + · exfalso; exact h_1 (hij.trans h_2) + · apply hv (tsub_le_tsub hij le_rfl) + calc + ((∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) + + ∑ i ∈ Finset.range m, edist (f (v (i + 1))) (f (v i))) = + (∑ i ∈ Finset.range n, edist (f (w (i + 1))) (f (w i))) + + ∑ i ∈ Finset.range m, edist (f (w (n + 1 + i + 1))) (f (w (n + 1 + i))) := by + dsimp only [w] + congr 1 + · refine Finset.sum_congr rfl fun i hi => ?_ + simp only [Finset.mem_range] at hi + have : i + 1 ≤ n := Nat.succ_le_of_lt hi + simp [hi.le, this] + · refine Finset.sum_congr rfl fun i hi => ?_ + simp only [Finset.mem_range] at hi + have B : ¬n + 1 + i ≤ n := by omega + have A : ¬n + 1 + i + 1 ≤ n := fun h => B ((n + 1 + i).le_succ.trans h) + have C : n + 1 + i - n = i + 1 := by + rw [tsub_eq_iff_eq_add_of_le] + · abel + · exact n.le_succ.trans (n.succ.le_add_right i) + simp only [A, B, C, Nat.succ_sub_succ_eq_sub, if_false, add_tsub_cancel_left] + _ = (∑ i ∈ Finset.range n, edist (f (w (i + 1))) (f (w i))) + + ∑ i ∈ Finset.Ico (n + 1) (n + 1 + m), edist (f (w (i + 1))) (f (w i)) := by + congr 1 + rw [Finset.range_eq_Ico] + convert Finset.sum_Ico_add (fun i : ℕ => edist (f (w (i + 1))) (f (w i))) 0 m (n + 1) + using 3 <;> abel + _ ≤ ∑ i ∈ Finset.range (n + 1 + m), edist (f (w (i + 1))) (f (w i)) := by + rw [← Finset.sum_union] + · apply Finset.sum_le_sum_of_subset _ + rintro i hi + simp only [Finset.mem_union, Finset.mem_range, Finset.mem_Ico] at hi ⊢ + cases' hi with hi hi + · exact lt_of_lt_of_le hi (n.le_succ.trans (n.succ.le_add_right m)) + · exact hi.2 + · refine Finset.disjoint_left.2 fun i hi h'i => ?_ + simp only [Finset.mem_Ico, Finset.mem_range] at hi h'i + exact hi.not_lt (Nat.lt_of_succ_le h'i.left) + _ ≤ eVariationOn f (s ∪ t) := sum_le f _ hw wst + +/-- If a set `s` is to the left of a set `t`, and both contain the boundary point `x`, then +the variation of `f` along `s ∪ t` is the sum of the variations. -/ +theorem union (f : α → E) {s t : Set α} {x : α} (hs : IsGreatest s x) (ht : IsLeast t x) : + eVariationOn f (s ∪ t) = eVariationOn f s + eVariationOn f t := by + classical + apply le_antisymm _ (eVariationOn.add_le_union f fun a ha b hb => le_trans (hs.2 ha) (ht.2 hb)) + apply iSup_le _ + rintro ⟨n, ⟨u, hu, ust⟩⟩ + obtain ⟨v, m, hv, vst, xv, huv⟩ : ∃ (v : ℕ → α) (m : ℕ), + Monotone v ∧ (∀ i, v i ∈ s ∪ t) ∧ x ∈ v '' Iio m ∧ + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) ≤ + ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := + eVariationOn.add_point f (mem_union_left t hs.1) u hu ust n + obtain ⟨N, hN, Nx⟩ : ∃ N, N < m ∧ v N = x := xv + calc + (∑ j ∈ Finset.range n, edist (f (u (j + 1))) (f (u j))) ≤ + ∑ j ∈ Finset.range m, edist (f (v (j + 1))) (f (v j)) := + huv + _ = (∑ j ∈ Finset.Ico 0 N, edist (f (v (j + 1))) (f (v j))) + + ∑ j ∈ Finset.Ico N m, edist (f (v (j + 1))) (f (v j)) := by + rw [Finset.range_eq_Ico, Finset.sum_Ico_consecutive _ (zero_le _) hN.le] + _ ≤ eVariationOn f s + eVariationOn f t := by + refine add_le_add ?_ ?_ + · apply sum_le_of_monotoneOn_Icc _ (hv.monotoneOn _) fun i hi => ?_ + rcases vst i with (h | h); · exact h + have : v i = x := by + apply le_antisymm + · rw [← Nx]; exact hv hi.2 + · exact ht.2 h + rw [this] + exact hs.1 + · apply sum_le_of_monotoneOn_Icc _ (hv.monotoneOn _) fun i hi => ?_ + rcases vst i with (h | h); swap; · exact h + have : v i = x := by + apply le_antisymm + · exact hs.2 h + · rw [← Nx]; exact hv hi.1 + rw [this] + exact ht.1 + +theorem Icc_add_Icc (f : α → E) {s : Set α} {a b c : α} (hab : a ≤ b) (hbc : b ≤ c) (hb : b ∈ s) : + eVariationOn f (s ∩ Icc a b) + eVariationOn f (s ∩ Icc b c) = eVariationOn f (s ∩ Icc a c) := by + have A : IsGreatest (s ∩ Icc a b) b := + ⟨⟨hb, hab, le_rfl⟩, inter_subset_right.trans Icc_subset_Iic_self⟩ + have B : IsLeast (s ∩ Icc b c) b := + ⟨⟨hb, le_rfl, hbc⟩, inter_subset_right.trans Icc_subset_Ici_self⟩ + rw [← eVariationOn.union f A B, ← inter_union_distrib_left, Icc_union_Icc_eq_Icc hab hbc] + +section Monotone + +variable {β : Type*} [LinearOrder β] + +theorem comp_le_of_monotoneOn (f : α → E) {s : Set α} {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) + (φst : MapsTo φ t s) : eVariationOn (f ∘ φ) t ≤ eVariationOn f s := + iSup_le fun ⟨n, u, hu, ut⟩ => + le_iSup_of_le ⟨n, φ ∘ u, fun x y xy => hφ (ut x) (ut y) (hu xy), fun i => φst (ut i)⟩ le_rfl + +theorem comp_le_of_antitoneOn (f : α → E) {s : Set α} {t : Set β} (φ : β → α) (hφ : AntitoneOn φ t) + (φst : MapsTo φ t s) : eVariationOn (f ∘ φ) t ≤ eVariationOn f s := by + refine iSup_le ?_ + rintro ⟨n, u, hu, ut⟩ + rw [← Finset.sum_range_reflect] + refine (Finset.sum_congr rfl fun x hx => ?_).trans_le <| le_iSup_of_le + ⟨n, fun i => φ (u <| n - i), fun x y xy => hφ (ut _) (ut _) (hu <| Nat.sub_le_sub_left xy n), + fun i => φst (ut _)⟩ + le_rfl + rw [Finset.mem_range] at hx + dsimp only [Subtype.coe_mk, Function.comp_apply] + rw [edist_comm] + congr 4 <;> omega + +theorem comp_eq_of_monotoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) : + eVariationOn (f ∘ φ) t = eVariationOn f (φ '' t) := by + apply le_antisymm (comp_le_of_monotoneOn f φ hφ (mapsTo_image φ t)) + cases isEmpty_or_nonempty β + · convert zero_le (_ : ℝ≥0∞) + exact eVariationOn.subsingleton f <| + (subsingleton_of_subsingleton.image _).anti (surjOn_image φ t) + let ψ := φ.invFunOn t + have ψφs : EqOn (φ ∘ ψ) id (φ '' t) := (surjOn_image φ t).rightInvOn_invFunOn + have ψts : MapsTo ψ (φ '' t) t := (surjOn_image φ t).mapsTo_invFunOn + have hψ : MonotoneOn ψ (φ '' t) := Function.monotoneOn_of_rightInvOn_of_mapsTo hφ ψφs ψts + change eVariationOn (f ∘ id) (φ '' t) ≤ eVariationOn (f ∘ φ) t + rw [← eq_of_eqOn (ψφs.comp_left : EqOn (f ∘ φ ∘ ψ) (f ∘ id) (φ '' t))] + exact comp_le_of_monotoneOn _ ψ hψ ψts + +theorem comp_inter_Icc_eq_of_monotoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : MonotoneOn φ t) + {x y : β} (hx : x ∈ t) (hy : y ∈ t) : + eVariationOn (f ∘ φ) (t ∩ Icc x y) = eVariationOn f (φ '' t ∩ Icc (φ x) (φ y)) := by + rcases le_total x y with (h | h) + · convert comp_eq_of_monotoneOn f φ (hφ.mono Set.inter_subset_left) + apply le_antisymm + · rintro _ ⟨⟨u, us, rfl⟩, vφx, vφy⟩ + rcases le_total x u with (xu | ux) + · rcases le_total u y with (uy | yu) + · exact ⟨u, ⟨us, ⟨xu, uy⟩⟩, rfl⟩ + · rw [le_antisymm vφy (hφ hy us yu)] + exact ⟨y, ⟨hy, ⟨h, le_rfl⟩⟩, rfl⟩ + · rw [← le_antisymm vφx (hφ us hx ux)] + exact ⟨x, ⟨hx, ⟨le_rfl, h⟩⟩, rfl⟩ + · rintro _ ⟨u, ⟨⟨hu, xu, uy⟩, rfl⟩⟩ + exact ⟨⟨u, hu, rfl⟩, ⟨hφ hx hu xu, hφ hu hy uy⟩⟩ + · rw [eVariationOn.subsingleton, eVariationOn.subsingleton] + exacts [(Set.subsingleton_Icc_of_ge (hφ hy hx h)).anti Set.inter_subset_right, + (Set.subsingleton_Icc_of_ge h).anti Set.inter_subset_right] + +theorem comp_eq_of_antitoneOn (f : α → E) {t : Set β} (φ : β → α) (hφ : AntitoneOn φ t) : + eVariationOn (f ∘ φ) t = eVariationOn f (φ '' t) := by + apply le_antisymm (comp_le_of_antitoneOn f φ hφ (mapsTo_image φ t)) + cases isEmpty_or_nonempty β + · convert zero_le (_ : ℝ≥0∞) + exact eVariationOn.subsingleton f <| (subsingleton_of_subsingleton.image _).anti + (surjOn_image φ t) + let ψ := φ.invFunOn t + have ψφs : EqOn (φ ∘ ψ) id (φ '' t) := (surjOn_image φ t).rightInvOn_invFunOn + have ψts := (surjOn_image φ t).mapsTo_invFunOn + have hψ : AntitoneOn ψ (φ '' t) := Function.antitoneOn_of_rightInvOn_of_mapsTo hφ ψφs ψts + change eVariationOn (f ∘ id) (φ '' t) ≤ eVariationOn (f ∘ φ) t + rw [← eq_of_eqOn (ψφs.comp_left : EqOn (f ∘ φ ∘ ψ) (f ∘ id) (φ '' t))] + exact comp_le_of_antitoneOn _ ψ hψ ψts + +open OrderDual + +theorem comp_ofDual (f : α → E) (s : Set α) : + eVariationOn (f ∘ ofDual) (ofDual ⁻¹' s) = eVariationOn f s := by + convert comp_eq_of_antitoneOn f ofDual fun _ _ _ _ => id + simp only [Equiv.image_preimage] + +end Monotone + +end eVariationOn + +/-! ## Monotone functions and bounded variation -/ + +theorem MonotoneOn.eVariationOn_le {f : α → ℝ} {s : Set α} (hf : MonotoneOn f s) {a b : α} + (as : a ∈ s) (bs : b ∈ s) : eVariationOn f (s ∩ Icc a b) ≤ ENNReal.ofReal (f b - f a) := by + apply iSup_le _ + rintro ⟨n, ⟨u, hu, us⟩⟩ + calc + (∑ i ∈ Finset.range n, edist (f (u (i + 1))) (f (u i))) = + ∑ i ∈ Finset.range n, ENNReal.ofReal (f (u (i + 1)) - f (u i)) := by + refine Finset.sum_congr rfl fun i hi => ?_ + simp only [Finset.mem_range] at hi + rw [edist_dist, Real.dist_eq, abs_of_nonneg] + exact sub_nonneg_of_le (hf (us i).1 (us (i + 1)).1 (hu (Nat.le_succ _))) + _ = ENNReal.ofReal (∑ i ∈ Finset.range n, (f (u (i + 1)) - f (u i))) := by + rw [ENNReal.ofReal_sum_of_nonneg] + intro i _ + exact sub_nonneg_of_le (hf (us i).1 (us (i + 1)).1 (hu (Nat.le_succ _))) + _ = ENNReal.ofReal (f (u n) - f (u 0)) := by rw [Finset.sum_range_sub fun i => f (u i)] + _ ≤ ENNReal.ofReal (f b - f a) := by + apply ENNReal.ofReal_le_ofReal + exact sub_le_sub (hf (us n).1 bs (us n).2.2) (hf as (us 0).1 (us 0).2.1) + +theorem MonotoneOn.locallyBoundedVariationOn {f : α → ℝ} {s : Set α} (hf : MonotoneOn f s) : + LocallyBoundedVariationOn f s := fun _ _ as bs => + ((hf.eVariationOn_le as bs).trans_lt ENNReal.ofReal_lt_top).ne + +/-- The **signed** variation of `f` on the interval `Icc a b` intersected with the set `s`, +squashed to a real (therefore only really meaningful if the variation is finite) +-/ +noncomputable def variationOnFromTo (f : α → E) (s : Set α) (a b : α) : ℝ := + if a ≤ b then (eVariationOn f (s ∩ Icc a b)).toReal else -(eVariationOn f (s ∩ Icc b a)).toReal + +namespace variationOnFromTo + +variable (f : α → E) (s : Set α) + +protected theorem self (a : α) : variationOnFromTo f s a a = 0 := by + dsimp only [variationOnFromTo] + rw [if_pos le_rfl, Icc_self, eVariationOn.subsingleton, ENNReal.zero_toReal] + exact fun x hx y hy => hx.2.trans hy.2.symm + +protected theorem nonneg_of_le {a b : α} (h : a ≤ b) : 0 ≤ variationOnFromTo f s a b := by + simp only [variationOnFromTo, if_pos h, ENNReal.toReal_nonneg] + +protected theorem eq_neg_swap (a b : α) : + variationOnFromTo f s a b = -variationOnFromTo f s b a := by + rcases lt_trichotomy a b with (ab | rfl | ba) + · simp only [variationOnFromTo, if_pos ab.le, if_neg ab.not_le, neg_neg] + · simp only [variationOnFromTo.self, neg_zero] + · simp only [variationOnFromTo, if_pos ba.le, if_neg ba.not_le, neg_neg] + +protected theorem nonpos_of_ge {a b : α} (h : b ≤ a) : variationOnFromTo f s a b ≤ 0 := by + rw [variationOnFromTo.eq_neg_swap] + exact neg_nonpos_of_nonneg (variationOnFromTo.nonneg_of_le f s h) + +protected theorem eq_of_le {a b : α} (h : a ≤ b) : + variationOnFromTo f s a b = (eVariationOn f (s ∩ Icc a b)).toReal := + if_pos h + +protected theorem eq_of_ge {a b : α} (h : b ≤ a) : + variationOnFromTo f s a b = -(eVariationOn f (s ∩ Icc b a)).toReal := by + rw [variationOnFromTo.eq_neg_swap, neg_inj, variationOnFromTo.eq_of_le f s h] + +protected theorem add {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) {a b c : α} + (ha : a ∈ s) (hb : b ∈ s) (hc : c ∈ s) : + variationOnFromTo f s a b + variationOnFromTo f s b c = variationOnFromTo f s a c := by + symm + refine additive_of_isTotal ((· : α) ≤ ·) (variationOnFromTo f s) (· ∈ s) ?_ ?_ ha hb hc + · rintro x y _xs _ys + simp only [variationOnFromTo.eq_neg_swap f s y x, Subtype.coe_mk, add_neg_cancel, + forall_true_left] + · rintro x y z xy yz xs ys zs + rw [variationOnFromTo.eq_of_le f s xy, variationOnFromTo.eq_of_le f s yz, + variationOnFromTo.eq_of_le f s (xy.trans yz), + ← ENNReal.toReal_add (hf x y xs ys) (hf y z ys zs), eVariationOn.Icc_add_Icc f xy yz ys] + +variable {f s} in +protected theorem edist_zero_of_eq_zero (hf : LocallyBoundedVariationOn f s) + {a b : α} (ha : a ∈ s) (hb : b ∈ s) (h : variationOnFromTo f s a b = 0) : + edist (f a) (f b) = 0 := by + wlog h' : a ≤ b + · rw [edist_comm] + apply this hf hb ha _ (le_of_not_le h') + rw [variationOnFromTo.eq_neg_swap, h, neg_zero] + · apply le_antisymm _ (zero_le _) + rw [← ENNReal.ofReal_zero, ← h, variationOnFromTo.eq_of_le f s h', + ENNReal.ofReal_toReal (hf a b ha hb)] + apply eVariationOn.edist_le + exacts [⟨ha, ⟨le_rfl, h'⟩⟩, ⟨hb, ⟨h', le_rfl⟩⟩] + +protected theorem eq_left_iff {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) + {a b c : α} (ha : a ∈ s) (hb : b ∈ s) (hc : c ∈ s) : + variationOnFromTo f s a b = variationOnFromTo f s a c ↔ variationOnFromTo f s b c = 0 := by + simp only [← variationOnFromTo.add hf ha hb hc, self_eq_add_right] + +protected theorem eq_zero_iff_of_le {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) + {a b : α} (ha : a ∈ s) (hb : b ∈ s) (ab : a ≤ b) : + variationOnFromTo f s a b = 0 ↔ + ∀ ⦃x⦄ (_hx : x ∈ s ∩ Icc a b) ⦃y⦄ (_hy : y ∈ s ∩ Icc a b), edist (f x) (f y) = 0 := by + rw [variationOnFromTo.eq_of_le _ _ ab, ENNReal.toReal_eq_zero_iff, or_iff_left (hf a b ha hb), + eVariationOn.eq_zero_iff] + +protected theorem eq_zero_iff_of_ge {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) + {a b : α} (ha : a ∈ s) (hb : b ∈ s) (ba : b ≤ a) : + variationOnFromTo f s a b = 0 ↔ + ∀ ⦃x⦄ (_hx : x ∈ s ∩ Icc b a) ⦃y⦄ (_hy : y ∈ s ∩ Icc b a), edist (f x) (f y) = 0 := by + rw [variationOnFromTo.eq_of_ge _ _ ba, neg_eq_zero, ENNReal.toReal_eq_zero_iff, + or_iff_left (hf b a hb ha), eVariationOn.eq_zero_iff] + +protected theorem eq_zero_iff {f : α → E} {s : Set α} (hf : LocallyBoundedVariationOn f s) {a b : α} + (ha : a ∈ s) (hb : b ∈ s) : + variationOnFromTo f s a b = 0 ↔ + ∀ ⦃x⦄ (_hx : x ∈ s ∩ uIcc a b) ⦃y⦄ (_hy : y ∈ s ∩ uIcc a b), edist (f x) (f y) = 0 := by + rcases le_total a b with (ab | ba) + · rw [uIcc_of_le ab] + exact variationOnFromTo.eq_zero_iff_of_le hf ha hb ab + · rw [uIcc_of_ge ba] + exact variationOnFromTo.eq_zero_iff_of_ge hf ha hb ba + +variable {f} {s} + +protected theorem monotoneOn (hf : LocallyBoundedVariationOn f s) {a : α} (as : a ∈ s) : + MonotoneOn (variationOnFromTo f s a) s := by + rintro b bs c cs bc + rw [← variationOnFromTo.add hf as bs cs] + exact le_add_of_nonneg_right (variationOnFromTo.nonneg_of_le f s bc) + +protected theorem antitoneOn (hf : LocallyBoundedVariationOn f s) {b : α} (bs : b ∈ s) : + AntitoneOn (fun a => variationOnFromTo f s a b) s := by + rintro a as c cs ac + dsimp only + rw [← variationOnFromTo.add hf as cs bs] + exact le_add_of_nonneg_left (variationOnFromTo.nonneg_of_le f s ac) + +protected theorem sub_self_monotoneOn {f : α → ℝ} {s : Set α} (hf : LocallyBoundedVariationOn f s) + {a : α} (as : a ∈ s) : MonotoneOn (variationOnFromTo f s a - f) s := by + rintro b bs c cs bc + rw [Pi.sub_apply, Pi.sub_apply, le_sub_iff_add_le, add_comm_sub, ← le_sub_iff_add_le'] + calc + f c - f b ≤ |f c - f b| := le_abs_self _ + _ = dist (f b) (f c) := by rw [dist_comm, Real.dist_eq] + _ ≤ variationOnFromTo f s b c := by + rw [variationOnFromTo.eq_of_le f s bc, dist_edist] + apply ENNReal.toReal_mono (hf b c bs cs) + apply eVariationOn.edist_le f + exacts [⟨bs, le_rfl, bc⟩, ⟨cs, bc, le_rfl⟩] + _ = variationOnFromTo f s a c - variationOnFromTo f s a b := by + rw [← variationOnFromTo.add hf as bs cs, add_sub_cancel_left] + +protected theorem comp_eq_of_monotoneOn {β : Type*} [LinearOrder β] (f : α → E) {t : Set β} + (φ : β → α) (hφ : MonotoneOn φ t) {x y : β} (hx : x ∈ t) (hy : y ∈ t) : + variationOnFromTo (f ∘ φ) t x y = variationOnFromTo f (φ '' t) (φ x) (φ y) := by + rcases le_total x y with (h | h) + · rw [variationOnFromTo.eq_of_le _ _ h, variationOnFromTo.eq_of_le _ _ (hφ hx hy h), + eVariationOn.comp_inter_Icc_eq_of_monotoneOn f φ hφ hx hy] + · rw [variationOnFromTo.eq_of_ge _ _ h, variationOnFromTo.eq_of_ge _ _ (hφ hy hx h), + eVariationOn.comp_inter_Icc_eq_of_monotoneOn f φ hφ hy hx] + +end variationOnFromTo + +/-- If a real valued function has bounded variation on a set, then it is a difference of monotone +functions there. -/ +theorem LocallyBoundedVariationOn.exists_monotoneOn_sub_monotoneOn {f : α → ℝ} {s : Set α} + (h : LocallyBoundedVariationOn f s) : + ∃ p q : α → ℝ, MonotoneOn p s ∧ MonotoneOn q s ∧ f = p - q := by + rcases eq_empty_or_nonempty s with (rfl | ⟨c, cs⟩) + · exact ⟨f, 0, subsingleton_empty.monotoneOn _, subsingleton_empty.monotoneOn _, + (sub_zero f).symm⟩ + · exact ⟨_, _, variationOnFromTo.monotoneOn h cs, variationOnFromTo.sub_self_monotoneOn h cs, + (sub_sub_cancel _ _).symm⟩ + +/-! ## Lipschitz functions and bounded variation -/ + +section LipschitzOnWith + +variable {F : Type*} [PseudoEMetricSpace F] + +theorem LipschitzOnWith.comp_eVariationOn_le {f : E → F} {C : ℝ≥0} {t : Set E} + (h : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) : + eVariationOn (f ∘ g) s ≤ C * eVariationOn g s := by + apply iSup_le _ + rintro ⟨n, ⟨u, hu, us⟩⟩ + calc + (∑ i ∈ Finset.range n, edist (f (g (u (i + 1)))) (f (g (u i)))) ≤ + ∑ i ∈ Finset.range n, C * edist (g (u (i + 1))) (g (u i)) := + Finset.sum_le_sum fun i _ => h (hg (us _)) (hg (us _)) + _ = C * ∑ i ∈ Finset.range n, edist (g (u (i + 1))) (g (u i)) := by rw [Finset.mul_sum] + _ ≤ C * eVariationOn g s := mul_le_mul_left' (eVariationOn.sum_le _ _ hu us) _ + +theorem LipschitzOnWith.comp_boundedVariationOn {f : E → F} {C : ℝ≥0} {t : Set E} + (hf : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) + (h : BoundedVariationOn g s) : BoundedVariationOn (f ∘ g) s := + ne_top_of_le_ne_top (ENNReal.mul_ne_top ENNReal.coe_ne_top h) (hf.comp_eVariationOn_le hg) + +theorem LipschitzOnWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥0} {t : Set E} + (hf : LipschitzOnWith C f t) {g : α → E} {s : Set α} (hg : MapsTo g s t) + (h : LocallyBoundedVariationOn g s) : LocallyBoundedVariationOn (f ∘ g) s := + fun x y xs ys => + hf.comp_boundedVariationOn (hg.mono_left inter_subset_left) (h x y xs ys) + +theorem LipschitzWith.comp_boundedVariationOn {f : E → F} {C : ℝ≥0} (hf : LipschitzWith C f) + {g : α → E} {s : Set α} (h : BoundedVariationOn g s) : BoundedVariationOn (f ∘ g) s := + hf.lipschitzOnWith.comp_boundedVariationOn (mapsTo_univ _ _) h + +theorem LipschitzWith.comp_locallyBoundedVariationOn {f : E → F} {C : ℝ≥0} + (hf : LipschitzWith C f) {g : α → E} {s : Set α} (h : LocallyBoundedVariationOn g s) : + LocallyBoundedVariationOn (f ∘ g) s := + hf.lipschitzOnWith.comp_locallyBoundedVariationOn (mapsTo_univ _ _) h + +theorem LipschitzOnWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} {s : Set ℝ} + (hf : LipschitzOnWith C f s) : LocallyBoundedVariationOn f s := + hf.comp_locallyBoundedVariationOn (mapsTo_id _) + (@monotoneOn_id ℝ _ s).locallyBoundedVariationOn + +theorem LipschitzWith.locallyBoundedVariationOn {f : ℝ → E} {C : ℝ≥0} (hf : LipschitzWith C f) + (s : Set ℝ) : LocallyBoundedVariationOn f s := + hf.lipschitzOnWith.locallyBoundedVariationOn + +end LipschitzOnWith diff --git a/Mathlib/Topology/EMetricSpace/Lipschitz.lean b/Mathlib/Topology/EMetricSpace/Lipschitz.lean index a9c56f4bc73d9..3be6db91a4e89 100644 --- a/Mathlib/Topology/EMetricSpace/Lipschitz.lean +++ b/Mathlib/Topology/EMetricSpace/Lipschitz.lean @@ -320,7 +320,7 @@ protected theorem prod {g : α → γ} {Kf Kg : ℝ≥0} (hf : LipschitzOnWith K theorem ediam_image2_le (f : α → β → γ) {K₁ K₂ : ℝ≥0} (s : Set α) (t : Set β) (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 - simp only [EMetric.diam_le_iff, forall_image2_iff] + simp only [EMetric.diam_le_iff, forall_mem_image2] intro a₁ ha₁ b₁ hb₁ a₂ ha₂ b₂ hb₂ refine (edist_triangle _ (f a₂ b₁) _).trans ?_ exact diff --git a/Mathlib/Topology/FiberBundle/Constructions.lean b/Mathlib/Topology/FiberBundle/Constructions.lean index 21d63b4d3c851..a123634cbb964 100644 --- a/Mathlib/Topology/FiberBundle/Constructions.lean +++ b/Mathlib/Topology/FiberBundle/Constructions.lean @@ -148,7 +148,7 @@ theorem Prod.continuous_to_fun : ContinuousOn (Prod.toFun' e₁ e₂) · rw [e₁.source_eq, e₂.source_eq] exact mapsTo_preimage _ _ rintro ⟨b, v₁, v₂⟩ ⟨hb₁, _⟩ - simp only [f₃, Prod.toFun', Prod.mk.inj_iff, Function.comp_apply, and_true] + simp only [f₁, f₂, f₃, Prod.toFun', Prod.mk.inj_iff, Function.comp_apply, and_true] rw [e₁.coe_fst] rw [e₁.source_eq, mem_preimage] exact hb₁ diff --git a/Mathlib/Topology/Gluing.lean b/Mathlib/Topology/Gluing.lean index c5385f98801ee..9af7fc85de01f 100644 --- a/Mathlib/Topology/Gluing.lean +++ b/Mathlib/Topology/Gluing.lean @@ -83,7 +83,7 @@ Most of the times it would be easier to use the constructor `TopCat.GlueData.mk' conditions are stated in a less categorical way. -/ -- Porting note (https://github.com/leanprover-community/mathlib4/issues/5171): removed @[nolint has_nonempty_instance] -structure GlueData extends GlueData TopCat where +structure GlueData extends CategoryTheory.GlueData TopCat where f_open : ∀ i j, IsOpenEmbedding (f i j) f_mono i j := (TopCat.mono_iff_injective _).mpr (f_open i j).isEmbedding.injective @@ -100,11 +100,9 @@ theorem isOpen_iff (U : Set 𝖣.glued) : IsOpen U ↔ ∀ i, IsOpen (𝖣.ι i delta CategoryTheory.GlueData.ι simp_rw [← Multicoequalizer.ι_sigmaπ 𝖣.diagram] rw [← (homeoOfIso (Multicoequalizer.isoCoequalizer 𝖣.diagram).symm).isOpen_preimage] - rw [coequalizer_isOpen_iff] + rw [coequalizer_isOpen_iff, colimit_isOpen_iff.{u}] dsimp only [GlueData.diagram_l, GlueData.diagram_left, GlueData.diagram_r, GlueData.diagram_right, parallelPair_obj_one] - rw [colimit_isOpen_iff.{_,u}] -- Porting note: changed `.{u}` to `.{_,u}`. fun fact: the proof - -- breaks down if this `rw` is merged with the `rw` above. constructor · intro h j; exact h ⟨j⟩ · intro h j; cases j; apply h @@ -274,17 +272,14 @@ theorem preimage_image_eq_image' (i j : D.J) (U : Set (𝖣.U i)) : -- Porting note: `show` was not needed, since `rw [← Set.image_image]` worked. show (fun x => ((forget TopCat).map _ ((forget TopCat).map _ x))) '' _ = _ rw [← Set.image_image] - -- Porting note: `congr 1` was here, instead of `congr_arg`, however, it did nothing. - refine congr_arg ?_ ?_ + congr! 1 rw [← Set.eq_preimage_iff_image_eq, Set.preimage_preimage] · change _ = (D.t i j ≫ D.t j i ≫ _) ⁻¹' _ rw [𝖣.t_inv_assoc] rw [← isIso_iff_bijective] apply (forget TopCat).map_isIso --- Porting note: the goal was simply `IsOpen (𝖣.ι i '' U)`. --- I had to manually add the explicit type ascription. -theorem open_image_open (i : D.J) (U : Opens (𝖣.U i)) : IsOpen (𝖣.ι i '' (U : Set (D.U i))) := by +theorem open_image_open (i : D.J) (U : Opens (𝖣.U i)) : IsOpen (𝖣.ι i '' U) := by rw [isOpen_iff] intro j rw [preimage_image_eq_image] @@ -393,15 +388,8 @@ def ofOpenSubsets : TopCat.GlueData.{u} := { J U := fun i => (Opens.toTopCat <| TopCat.of α).obj (U i) V := fun _ j => (Opens.map <| Opens.inclusion' _).obj (U j) - t := fun i j => ⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, by - -- Porting note: was `continuity`, see https://github.com/leanprover-community/mathlib4/issues/5030 - refine Continuous.subtype_mk ?_ ?_ - refine Continuous.subtype_mk ?_ ?_ - continuity⟩ - V_id := fun i => by - ext - -- Porting note: no longer needed `cases U i`! - simp + t := fun i j => ⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, by fun_prop⟩ + V_id := fun i => by ext; simp t_id := fun i => by ext; rfl t_inter := fun _ _ _ _ hx => hx cocycle := fun _ _ _ _ _ => rfl } @@ -445,8 +433,7 @@ theorem fromOpenSubsetsGlue_isOpenMap : IsOpenMap (fromOpenSubsetsGlue U) := by apply (Opens.isOpenEmbedding (X := TopCat.of α) (U i)).isOpenMap convert hs i using 1 erw [← ι_fromOpenSubsetsGlue, coe_comp, Set.preimage_comp] - -- porting note: `congr 1` did nothing, so I replaced it with `apply congr_arg` - apply congr_arg + congr! 1 exact Set.preimage_image_eq _ (fromOpenSubsetsGlue_injective U) · refine ⟨Set.mem_image_of_mem _ hx, ?_⟩ rw [ι_fromOpenSubsetsGlue_apply] diff --git a/Mathlib/Topology/Homeomorph.lean b/Mathlib/Topology/Homeomorph.lean index f536c0c7e30dc..b7e93c00e5acf 100644 --- a/Mathlib/Topology/Homeomorph.lean +++ b/Mathlib/Topology/Homeomorph.lean @@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Johannes Hölzl, Patrick Massot, Sébastien Gouëzel, Zhouhang Zhou, Reid Barton -/ import Mathlib.Logic.Equiv.Fin -import Mathlib.Topology.DenseEmbedding -import Mathlib.Topology.Support +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.Connected.LocallyConnected +import Mathlib.Topology.DenseEmbedding /-! # Homeomorphisms @@ -198,6 +198,9 @@ theorem image_preimage (h : X ≃ₜ Y) (s : Set Y) : h '' (h ⁻¹' s) = s := theorem preimage_image (h : X ≃ₜ Y) (s : Set X) : h ⁻¹' (h '' s) = s := h.toEquiv.preimage_image s +theorem image_eq_preimage (h : X ≃ₜ Y) (s : Set X) : h '' s = h.symm ⁻¹' s := + h.toEquiv.image_eq_preimage s + lemma image_compl (h : X ≃ₜ Y) (s : Set X) : h '' (sᶜ) = (h '' s)ᶜ := h.toEquiv.image_compl s diff --git a/Mathlib/Topology/IndicatorConstPointwise.lean b/Mathlib/Topology/IndicatorConstPointwise.lean index deb980b52a7e8..0ec0a97c72bba 100644 --- a/Mathlib/Topology/IndicatorConstPointwise.lean +++ b/Mathlib/Topology/IndicatorConstPointwise.lean @@ -3,6 +3,7 @@ Copyright (c) 2023 Kalle Kytölä. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Kalle Kytölä -/ +import Mathlib.Algebra.Group.Indicator import Mathlib.Topology.Separation.Basic /-! diff --git a/Mathlib/Topology/Instances/EReal.lean b/Mathlib/Topology/Instances/EReal.lean index 746c9fd365e5b..3af0b2ab4b18d 100644 --- a/Mathlib/Topology/Instances/EReal.lean +++ b/Mathlib/Topology/Instances/EReal.lean @@ -7,6 +7,7 @@ import Mathlib.Data.Rat.Encodable import Mathlib.Data.Real.EReal import Mathlib.Topology.Instances.ENNReal import Mathlib.Topology.Order.MonotoneContinuity +import Mathlib.Topology.Semicontinuous /-! # Topological structure on `EReal` @@ -441,4 +442,12 @@ theorem continuousAt_mul {p : EReal × EReal} (h₁ : p.1 ≠ 0 ∨ p.2 ≠ ⊥) exact continuousAt_mul_top_ne_zero h₄ · exact continuousAt_mul_top_top +lemma lowerSemicontinuous_add : LowerSemicontinuous fun p : EReal × EReal ↦ p.1 + p.2 := by + intro x y + by_cases hx₁ : x.1 = ⊥ + · simp [hx₁] + by_cases hx₂ : x.2 = ⊥ + · simp [hx₂] + · exact continuousAt_add (.inr hx₂) (.inl hx₁) |>.lowerSemicontinuousAt _ + end EReal diff --git a/Mathlib/Topology/Instances/Matrix.lean b/Mathlib/Topology/Instances/Matrix.lean index dc4f941c6159d..6dbd675168fb4 100644 --- a/Mathlib/Topology/Instances/Matrix.lean +++ b/Mathlib/Topology/Instances/Matrix.lean @@ -179,13 +179,16 @@ theorem Continuous.matrix_det [Fintype n] [DecidableEq n] [CommRing R] [Topologi exact continuous_finset_prod _ fun l _ => hA.matrix_elem _ _ @[continuity] -theorem Continuous.matrix_updateColumn [DecidableEq n] (i : n) {A : X → Matrix m n R} +theorem Continuous.matrix_updateCol [DecidableEq n] (i : n) {A : X → Matrix m n R} {B : X → m → R} (hA : Continuous A) (hB : Continuous B) : - Continuous fun x => (A x).updateColumn i (B x) := + Continuous fun x => (A x).updateCol i (B x) := continuous_matrix fun _j k => (continuous_apply k).comp <| ((continuous_apply _).comp hA).update i ((continuous_apply _).comp hB) +@[deprecated (since := "2024-12-11")] +alias Continuous.matrix_updateColumn := Continuous.matrix_updateCol + @[continuity] theorem Continuous.matrix_updateRow [DecidableEq m] (i : m) {A : X → Matrix m n R} {B : X → n → R} (hA : Continuous A) (hB : Continuous B) : Continuous fun x => (A x).updateRow i (B x) := @@ -195,13 +198,13 @@ theorem Continuous.matrix_updateRow [DecidableEq m] (i : m) {A : X → Matrix m theorem Continuous.matrix_cramer [Fintype n] [DecidableEq n] [CommRing R] [TopologicalRing R] {A : X → Matrix n n R} {B : X → n → R} (hA : Continuous A) (hB : Continuous B) : Continuous fun x => cramer (A x) (B x) := - continuous_pi fun _ => (hA.matrix_updateColumn _ hB).matrix_det + continuous_pi fun _ => (hA.matrix_updateCol _ hB).matrix_det @[continuity] theorem Continuous.matrix_adjugate [Fintype n] [DecidableEq n] [CommRing R] [TopologicalRing R] {A : X → Matrix n n R} (hA : Continuous A) : Continuous fun x => (A x).adjugate := continuous_matrix fun _j k => - (hA.matrix_transpose.matrix_updateColumn k continuous_const).matrix_det + (hA.matrix_transpose.matrix_updateCol k continuous_const).matrix_det /-- When `Ring.inverse` is continuous at the determinant (such as in a `NormedRing`, or a topological field), so is `Matrix.inv`. -/ diff --git a/Mathlib/Topology/Instances/TrivSqZeroExt.lean b/Mathlib/Topology/Instances/TrivSqZeroExt.lean index b8a913a8e6a65..5a6add1956758 100644 --- a/Mathlib/Topology/Instances/TrivSqZeroExt.lean +++ b/Mathlib/Topology/Instances/TrivSqZeroExt.lean @@ -42,14 +42,12 @@ instance instTopologicalSpace : TopologicalSpace (tsze R M) := instance [T2Space R] [T2Space M] : T2Space (tsze R M) := Prod.t2Space -theorem nhds_def (x : tsze R M) : 𝓝 x = (𝓝 x.fst).prod (𝓝 x.snd) := by - cases x using Prod.rec - exact nhds_prod_eq +theorem nhds_def (x : tsze R M) : 𝓝 x = 𝓝 x.fst ×ˢ 𝓝 x.snd := nhds_prod_eq -theorem nhds_inl [Zero M] (x : R) : 𝓝 (inl x : tsze R M) = (𝓝 x).prod (𝓝 0) := +theorem nhds_inl [Zero M] (x : R) : 𝓝 (inl x : tsze R M) = 𝓝 x ×ˢ 𝓝 0 := nhds_def _ -theorem nhds_inr [Zero R] (m : M) : 𝓝 (inr m : tsze R M) = (𝓝 0).prod (𝓝 m) := +theorem nhds_inr [Zero R] (m : M) : 𝓝 (inr m : tsze R M) = 𝓝 0 ×ˢ 𝓝 m := nhds_def _ nonrec theorem continuous_fst : Continuous (fst : tsze R M → R) := diff --git a/Mathlib/Topology/List.lean b/Mathlib/Topology/List.lean index 0620deab85315..4ca0d9581282a 100644 --- a/Mathlib/Topology/List.lean +++ b/Mathlib/Topology/List.lean @@ -184,16 +184,16 @@ open List open Mathlib (Vector) -instance (n : ℕ) : TopologicalSpace (Vector α n) := by unfold Vector; infer_instance +instance (n : ℕ) : TopologicalSpace (Mathlib.Vector α n) := by unfold Mathlib.Vector; infer_instance -theorem tendsto_cons {n : ℕ} {a : α} {l : Vector α n} : - Tendsto (fun p : α × Vector α n => p.1 ::ᵥ p.2) (𝓝 a ×ˢ 𝓝 l) (𝓝 (a ::ᵥ l)) := by +theorem tendsto_cons {n : ℕ} {a : α} {l : Mathlib.Vector α n} : + Tendsto (fun p : α × Mathlib.Vector α n => p.1 ::ᵥ p.2) (𝓝 a ×ˢ 𝓝 l) (𝓝 (a ::ᵥ l)) := by rw [tendsto_subtype_rng, Vector.cons_val] exact tendsto_fst.cons (Tendsto.comp continuousAt_subtype_val tendsto_snd) theorem tendsto_insertIdx {n : ℕ} {i : Fin (n + 1)} {a : α} : - ∀ {l : Vector α n}, - Tendsto (fun p : α × Vector α n => Vector.insertIdx p.1 i p.2) (𝓝 a ×ˢ 𝓝 l) + ∀ {l : Mathlib.Vector α n}, + Tendsto (fun p : α × Mathlib.Vector α n => Vector.insertIdx p.1 i p.2) (𝓝 a ×ˢ 𝓝 l) (𝓝 (Vector.insertIdx a i l)) | ⟨l, hl⟩ => by rw [Vector.insertIdx, tendsto_subtype_rng] @@ -204,29 +204,29 @@ theorem tendsto_insertIdx {n : ℕ} {i : Fin (n + 1)} {a : α} : /-- Continuity of `Vector.insertIdx`. -/ theorem continuous_insertIdx' {n : ℕ} {i : Fin (n + 1)} : - Continuous fun p : α × Vector α n => Vector.insertIdx p.1 i p.2 := + Continuous fun p : α × Mathlib.Vector α n => Vector.insertIdx p.1 i p.2 := continuous_iff_continuousAt.mpr fun ⟨a, l⟩ => by rw [ContinuousAt, nhds_prod_eq]; exact tendsto_insertIdx @[deprecated (since := "2024-10-21")] alias continuous_insertNth' := continuous_insertIdx' -theorem continuous_insertIdx {n : ℕ} {i : Fin (n + 1)} {f : β → α} {g : β → Vector α n} +theorem continuous_insertIdx {n : ℕ} {i : Fin (n + 1)} {f : β → α} {g : β → Mathlib.Vector α n} (hf : Continuous f) (hg : Continuous g) : Continuous fun b => Vector.insertIdx (f b) i (g b) := continuous_insertIdx'.comp (hf.prod_mk hg : _) @[deprecated (since := "2024-10-21")] alias continuous_insertNth := continuous_insertIdx theorem continuousAt_eraseIdx {n : ℕ} {i : Fin (n + 1)} : - ∀ {l : Vector α (n + 1)}, ContinuousAt (Vector.eraseIdx i) l + ∀ {l : Mathlib.Vector α (n + 1)}, ContinuousAt (Mathlib.Vector.eraseIdx i) l | ⟨l, hl⟩ => by - rw [ContinuousAt, Vector.eraseIdx, tendsto_subtype_rng] + rw [ContinuousAt, Mathlib.Vector.eraseIdx, tendsto_subtype_rng] simp only [Vector.eraseIdx_val] exact Tendsto.comp List.tendsto_eraseIdx continuousAt_subtype_val @[deprecated (since := "2024-05-04")] alias continuousAt_removeNth := continuousAt_eraseIdx theorem continuous_eraseIdx {n : ℕ} {i : Fin (n + 1)} : - Continuous (Vector.eraseIdx i : Vector α (n + 1) → Vector α n) := + Continuous (Mathlib.Vector.eraseIdx i : Mathlib.Vector α (n + 1) → Mathlib.Vector α n) := continuous_iff_continuousAt.mpr fun ⟨_a, _l⟩ => continuousAt_eraseIdx @[deprecated (since := "2024-05-04")] alias continuous_removeNth := continuous_eraseIdx diff --git a/Mathlib/Topology/MetricSpace/ProperSpace.lean b/Mathlib/Topology/MetricSpace/ProperSpace.lean index 3868c4d9c6a97..69d91fcc8b806 100644 --- a/Mathlib/Topology/MetricSpace/ProperSpace.lean +++ b/Mathlib/Topology/MetricSpace/ProperSpace.lean @@ -4,11 +4,11 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Sébastien Gouëzel -/ -import Mathlib.Topology.Order.IsLUB -import Mathlib.Topology.Support +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.MetricSpace.Pseudo.Basic import Mathlib.Topology.MetricSpace.Pseudo.Lemmas import Mathlib.Topology.MetricSpace.Pseudo.Pi +import Mathlib.Topology.Order.IsLUB /-! ## Proper spaces diff --git a/Mathlib/Topology/NhdsSet.lean b/Mathlib/Topology/NhdsSet.lean index 9b361653607e1..f0aa111474378 100644 --- a/Mathlib/Topology/NhdsSet.lean +++ b/Mathlib/Topology/NhdsSet.lean @@ -122,7 +122,7 @@ theorem mem_nhdsSet_empty : s ∈ 𝓝ˢ (∅ : Set X) := by simp @[simp] theorem nhdsSet_univ : 𝓝ˢ (univ : Set X) = ⊤ := by rw [isOpen_univ.nhdsSet_eq, principal_univ] -@[mono] +@[gcongr, mono] theorem nhdsSet_mono (h : s ⊆ t) : 𝓝ˢ s ≤ 𝓝ˢ t := sSup_le_sSup <| image_subset _ h diff --git a/Mathlib/Topology/OmegaCompletePartialOrder.lean b/Mathlib/Topology/OmegaCompletePartialOrder.lean index c7890d3939837..cce0eb4e71f4a 100644 --- a/Mathlib/Topology/OmegaCompletePartialOrder.lean +++ b/Mathlib/Topology/OmegaCompletePartialOrder.lean @@ -106,7 +106,7 @@ theorem notBelow_isOpen : IsOpen (notBelow y) := by end notBelow -open Scott hiding IsOpen +open Scott hiding IsOpen IsOpen.isUpperSet open OmegaCompletePartialOrder diff --git a/Mathlib/Topology/Order/Basic.lean b/Mathlib/Topology/Order/Basic.lean index 59abac51b6b7c..38a08ce558259 100644 --- a/Mathlib/Topology/Order/Basic.lean +++ b/Mathlib/Topology/Order/Basic.lean @@ -472,9 +472,10 @@ theorem atBot_le_nhds_bot [OrderBot α] : (atBot : Filter α) ≤ 𝓝 ⊥ := by rw [OrderBot.atBot_eq] apply pure_le_nhds +set_option linter.deprecated false in @[deprecated OrderTop.atTop_eq (since := "2024-02-14")] theorem atTop_le_nhds_top [OrderTop α] : (atTop : Filter α) ≤ 𝓝 ⊤ := - set_option linter.deprecated false in @atBot_le_nhds_bot αᵒᵈ _ _ _ + @atBot_le_nhds_bot αᵒᵈ _ _ _ variable (α) diff --git a/Mathlib/Topology/Order/Compact.lean b/Mathlib/Topology/Order/Compact.lean index bf30e3961311d..c8c4297800a48 100644 --- a/Mathlib/Topology/Order/Compact.lean +++ b/Mathlib/Topology/Order/Compact.lean @@ -3,10 +3,10 @@ Copyright (c) 2021 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Yury Kudryashov -/ -import Mathlib.Topology.Order.LocalExtr +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.Order.IntermediateValue -import Mathlib.Topology.Support import Mathlib.Topology.Order.IsLUB +import Mathlib.Topology.Order.LocalExtr /-! # Compactness of a closed interval diff --git a/Mathlib/Topology/Order/LeftRight.lean b/Mathlib/Topology/Order/LeftRight.lean index e18f75c1f4fa6..065632d5f1161 100644 --- a/Mathlib/Topology/Order/LeftRight.lean +++ b/Mathlib/Topology/Order/LeftRight.lean @@ -3,6 +3,7 @@ Copyright (c) 2021 Anatole Dedecker. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Anatole Dedecker -/ +import Mathlib.Order.Antichain import Mathlib.Topology.ContinuousOn /-! diff --git a/Mathlib/Topology/Separation/Basic.lean b/Mathlib/Topology/Separation/Basic.lean index b56a3a27aa9a9..827ce1e31923c 100644 --- a/Mathlib/Topology/Separation/Basic.lean +++ b/Mathlib/Topology/Separation/Basic.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 -/ +import Mathlib.Algebra.Group.Support import Mathlib.Topology.Compactness.Lindelof import Mathlib.Topology.Compactness.SigmaCompact import Mathlib.Topology.Connected.TotallyDisconnected diff --git a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean index 196cd67b22551..0ad5004a30a59 100644 --- a/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean +++ b/Mathlib/Topology/Sheaves/SheafCondition/PairwiseIntersections.lean @@ -344,7 +344,7 @@ def interUnionPullbackConeLift : s.pt ⟶ F.1.obj (op (U ⊔ V)) := by rcases j with (⟨⟨_ | _⟩⟩ | ⟨⟨_ | _⟩, ⟨_⟩⟩) <;> rcases g with ⟨⟩ <;> dsimp [Pairwise.diagram] <;> - simp only [Category.id_comp, s.condition, CategoryTheory.Functor.map_id, Category.comp_id] + simp only [ι, Category.id_comp, s.condition, CategoryTheory.Functor.map_id, Category.comp_id] rw [← cancel_mono (F.1.map (eqToHom <| inf_comm U V : U ⊓ V ⟶ _).op), Category.assoc, Category.assoc, ← F.1.map_comp, ← F.1.map_comp] exact s.condition.symm diff --git a/Mathlib/Topology/UniformSpace/Basic.lean b/Mathlib/Topology/UniformSpace/Basic.lean index 5534b8ebfe86d..ef9363d4616d6 100644 --- a/Mathlib/Topology/UniformSpace/Basic.lean +++ b/Mathlib/Topology/UniformSpace/Basic.lean @@ -1217,6 +1217,10 @@ theorem UniformContinuous.continuous [UniformSpace α] [UniformSpace β] {f : α instance ULift.uniformSpace [UniformSpace α] : UniformSpace (ULift α) := UniformSpace.comap ULift.down ‹_› +/-- Uniform space structure on `αᵒᵈ`. -/ +instance OrderDual.instUniformSpace [UniformSpace α] : UniformSpace (αᵒᵈ) := + ‹UniformSpace α› + section UniformContinuousInfi -- Porting note: renamed for dot notation; add an `iff` lemma? @@ -1393,8 +1397,7 @@ instance [UniformSpace α] [IsCountablyGenerated (𝓤 α)] theorem uniformity_prod_eq_comap_prod [UniformSpace α] [UniformSpace β] : 𝓤 (α × β) = comap (fun p : (α × β) × α × β => ((p.1.1, p.2.1), (p.1.2, p.2.2))) (𝓤 α ×ˢ 𝓤 β) := by - dsimp [SProd.sprod] - rw [uniformity_prod, Filter.prod, Filter.comap_inf, Filter.comap_comap, Filter.comap_comap]; rfl + simp_rw [uniformity_prod, prod_eq_inf, Filter.comap_inf, Filter.comap_comap, Function.comp_def] theorem uniformity_prod_eq_prod [UniformSpace α] [UniformSpace β] : 𝓤 (α × β) = map (fun p : (α × α) × β × β => ((p.1.1, p.2.1), (p.1.2, p.2.2))) (𝓤 α ×ˢ 𝓤 β) := by diff --git a/Mathlib/Topology/UniformSpace/Completion.lean b/Mathlib/Topology/UniformSpace/Completion.lean index b10f71d844724..7e1f98e7b1de7 100644 --- a/Mathlib/Topology/UniformSpace/Completion.lean +++ b/Mathlib/Topology/UniformSpace/Completion.lean @@ -80,7 +80,7 @@ private theorem symm_gen : map Prod.swap ((𝓤 α).lift' gen) ≤ (𝓤 α).lif { p : CauchyFilter α × CauchyFilter α | s ∈ (p.2.val ×ˢ p.1.val : Filter (α × α)) } have h₁ : map Prod.swap ((𝓤 α).lift' gen) = (𝓤 α).lift' f := by delta gen - simp [map_lift'_eq, monotone_setOf, Filter.monotone_mem, Function.comp_def, + simp [f, map_lift'_eq, monotone_setOf, Filter.monotone_mem, Function.comp_def, image_swap_eq_preimage_swap] have h₂ : (𝓤 α).lift' f ≤ (𝓤 α).lift' gen := uniformity_lift_le_swap @@ -204,9 +204,6 @@ theorem nonempty_cauchyFilter_iff : Nonempty (CauchyFilter α) ↔ Nonempty α : section --- Porting note: I commented this --- set_option eqn_compiler.zeta true - instance : CompleteSpace (CauchyFilter α) := completeSpace_extension isUniformInducing_pureCauchy denseRange_pureCauchy fun f hf => let f' : CauchyFilter α := ⟨f, hf⟩ @@ -313,9 +310,7 @@ instance completeSpace : CompleteSpace (Completion α) := instance t0Space : T0Space (Completion α) := SeparationQuotient.instT0Space -/-- The map from a uniform space to its completion. - -porting note: this was added to create a target for the `@[coe]` attribute. -/ +/-- The map from a uniform space to its completion. -/ @[coe] def coe' : α → Completion α := SeparationQuotient.mk ∘ pureCauchy /-- Automatic coercion from `α` to its completion. Not always injective. -/ @@ -460,8 +455,6 @@ theorem continuous_extension : Continuous (Completion.extension f) := end CompleteSpace -/- porting note: removed `@[simp]` because this lemma doesn't even trigger on itself in Lean 3 or -Lean 4 unless the user manually supplies the `hf` argument, so it is useless as a `simp` lemma. -/ theorem extension_coe [T0Space β] (hf : UniformContinuous f) (a : α) : (Completion.extension f) a = f a := cPkg.extend_coe hf a @@ -495,8 +488,6 @@ theorem uniformContinuous_map : UniformContinuous (Completion.map f) := theorem continuous_map : Continuous (Completion.map f) := cPkg.continuous_map cPkg f -/- porting note: removed `@[simp]` because this lemma doesn't even trigger on itself in Lean 3 or -Lean 4 unless the user manually supplies the `hf` argument, so it is useless as a `simp` lemma. -/ theorem map_coe (hf : UniformContinuous f) (a : α) : (Completion.map f) a = f a := cPkg.map_coe cPkg hf a @@ -512,11 +503,7 @@ theorem extension_map [CompleteSpace γ] [T0Space γ] {f : β → γ} {g : α (hf : UniformContinuous f) (hg : UniformContinuous g) : Completion.extension f ∘ Completion.map g = Completion.extension (f ∘ g) := Completion.ext (continuous_extension.comp continuous_map) continuous_extension <| by - intro a - -- Porting note: this is not provable by simp [hf, hg, hf.comp hg, map_coe, extension_coe], - -- but should be? - rw [extension_coe (hf.comp hg), Function.comp_apply, map_coe hg, extension_coe hf, - Function.comp_apply] + simp [hf, hg, hf.comp hg, map_coe, extension_coe] theorem map_comp {g : β → γ} {f : α → β} (hg : UniformContinuous g) (hf : UniformContinuous f) : Completion.map g ∘ Completion.map f = Completion.map (g ∘ f) := @@ -568,8 +555,6 @@ section T0Space variable [T0Space γ] {f} -/- porting note: removed `@[simp]` because this lemma doesn't even trigger on itself in Lean 3 or -Lean 4 unless the user manually supplies the `hf` argument, so it is useless as a `simp` lemma. -/ theorem extension₂_coe_coe (hf : UniformContinuous₂ f) (a : α) (b : β) : Completion.extension₂ f a b = f a b := cPkg.extension₂_coe_coe cPkg hf a b diff --git a/Mathlib/Topology/UniformSpace/Dini.lean b/Mathlib/Topology/UniformSpace/Dini.lean new file mode 100644 index 0000000000000..9e90b66608f20 --- /dev/null +++ b/Mathlib/Topology/UniformSpace/Dini.lean @@ -0,0 +1,159 @@ +/- +Copyright (c) 2024 Jireh Loreaux. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Jireh Loreaux +-/ +import Mathlib.Analysis.Normed.Order.Lattice +import Mathlib.Topology.ContinuousMap.Ordered +import Mathlib.Topology.UniformSpace.CompactConvergence + +/-! # Dini's Theorem + +This file proves Dini's theorem, which states that if `F n` is a monotone increasing sequence of +continuous real-valued functions on a compact set `s` converging pointwise to a continuous function +`f`, then `F n` converges uniformly to `f`. + +We generalize the codomain from `ℝ` to a normed lattice additive commutative group `G`. +This theorem is true in a different generality as well: when `G` is a linearly ordered topological +group with the order topology. This weakens the norm assumption, in exchange for strengthening to +a linear order. This separate generality is not included in this file, but that generality was +included in initial drafts of the original +[PR #19068](https://github.com/leanprover-community/mathlib4/pull/19068) and can be recovered if +necessary. + +The key idea of the proof is to use a particular basis of `𝓝 0` which consists of open sets that +are somehow monotone in the sense that if `s` is in the basis, and `0 ≤ x ≤ y`, then +`y ∈ s → x ∈ s`, and so the proof would work on any topological ordered group possessing +such a basis. In the case of a linearly ordered topological group with the order topology, this +basis is `nhds_basis_Ioo`. In the case of a normed lattice additive commutative group, this basis +is `nhds_basis_ball`, and the fact that this basis satisfies the monotonicity criterion +corresponds to `HasSolidNorm`. +-/ + +open Filter Topology + +variable {ι α G : Type*} [Preorder ι] [TopologicalSpace α] [NormedLatticeAddCommGroup G] + +section Unbundled + +open Metric + +variable {F : ι → α → G} {f : α → G} + +namespace Monotone + +/-- **Dini's theorem** If `F n` is a monotone increasing collection of continuous functions +converging pointwise to a continuous function `f`, then `F n` converges locally uniformly to `f`. -/ +lemma tendstoLocallyUniformly_of_forall_tendsto + (hF_cont : ∀ i, Continuous (F i)) (hF_mono : Monotone F) (hf : Continuous f) + (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoLocallyUniformly F f atTop := by + refine (atTop : Filter ι).eq_or_neBot.elim (fun h ↦ ?eq_bot) (fun _ ↦ ?_) + case eq_bot => simp [h, tendstoLocallyUniformly_iff_forall_tendsto] + have F_le_f (x : α) (n : ι) : F n x ≤ f x := by + refine ge_of_tendsto (h_tendsto x) ?_ + filter_upwards [Ici_mem_atTop n] with m hnm + exact hF_mono hnm x + simp_rw [Metric.tendstoLocallyUniformly_iff, dist_eq_norm'] + intro ε ε_pos x + simp_rw +singlePass [tendsto_iff_norm_sub_tendsto_zero] at h_tendsto + obtain ⟨n, hn⟩ := (h_tendsto x).eventually (eventually_lt_nhds ε_pos) |>.exists + refine ⟨{y | ‖F n y - f y‖ < ε}, ⟨isOpen_lt (by fun_prop) continuous_const |>.mem_nhds hn, ?_⟩⟩ + filter_upwards [eventually_ge_atTop n] with m hnm z hz + refine norm_le_norm_of_abs_le_abs ?_ |>.trans_lt hz + simp only [abs_of_nonpos (sub_nonpos_of_le (F_le_f _ _)), neg_sub, sub_le_sub_iff_left] + exact hF_mono hnm z + +/-- **Dini's theorem** If `F n` is a monotone increasing collection of continuous functions on a +set `s` converging pointwise to a continuous funciton `f`, then `F n` converges locally uniformly +to `f`. -/ +lemma tendstoLocallyUniformlyOn_of_forall_tendsto {s : Set α} + (hF_cont : ∀ i, ContinuousOn (F i) s) (hF_mono : ∀ x ∈ s, Monotone (F · x)) + (hf : ContinuousOn f s) (h_tendsto : ∀ x ∈ s, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoLocallyUniformlyOn F f atTop s := by + rw [tendstoLocallyUniformlyOn_iff_tendstoLocallyUniformly_comp_coe] + exact tendstoLocallyUniformly_of_forall_tendsto (hF_cont · |>.restrict) + (fun _ _ h x ↦ hF_mono _ x.2 h) hf.restrict (fun x ↦ h_tendsto x x.2) + +/-- **Dini's theorem** If `F n` is a monotone increasing collection of continuous functions on a +compact space converging pointwise to a continuous function `f`, then `F n` converges uniformly to +`f`. -/ +lemma tendstoUniformly_of_forall_tendsto [CompactSpace α] (hF_cont : ∀ i, Continuous (F i)) + (hF_mono : Monotone F) (hf : Continuous f) (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoUniformly F f atTop := + tendstoLocallyUniformly_iff_tendstoUniformly_of_compactSpace.mp <| + tendstoLocallyUniformly_of_forall_tendsto hF_cont hF_mono hf h_tendsto + +/-- **Dini's theorem** If `F n` is a monotone increasing collection of continuous functions on a +compact set `s` converging pointwise to a continuous function `f`, then `F n` converges uniformly +to `f`. -/ +lemma tendstoUniformlyOn_of_forall_tendsto {s : Set α} (hs : IsCompact s) + (hF_cont : ∀ i, ContinuousOn (F i) s) (hF_mono : ∀ x ∈ s, Monotone (F · x)) + (hf : ContinuousOn f s) (h_tendsto : ∀ x ∈ s, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoUniformlyOn F f atTop s := + tendstoLocallyUniformlyOn_iff_tendstoUniformlyOn_of_compact hs |>.mp <| + tendstoLocallyUniformlyOn_of_forall_tendsto hF_cont hF_mono hf h_tendsto + +end Monotone + +namespace Antitone + +/-- **Dini's theorem** If `F n` is a monotone decreasing collection of continuous functions on a +converging pointwise to a continuous function `f`, then `F n` converges locally uniformly to `f`. -/ +lemma tendstoLocallyUniformly_of_forall_tendsto + (hF_cont : ∀ i, Continuous (F i)) (hF_anti : Antitone F) (hf : Continuous f) + (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoLocallyUniformly F f atTop := + Monotone.tendstoLocallyUniformly_of_forall_tendsto (G := Gᵒᵈ) hF_cont hF_anti hf h_tendsto + +/-- **Dini's theorem** If `F n` is a monotone decreasing collection of continuous functions on a +set `s` converging pointwise to a continuous function `f`, then `F n` converges locally uniformly +to `f`. -/ +lemma tendstoLocallyUniformlyOn_of_forall_tendsto {s : Set α} + (hF_cont : ∀ i, ContinuousOn (F i) s) (hF_anti : ∀ x ∈ s, Antitone (F · x)) + (hf : ContinuousOn f s) (h_tendsto : ∀ x ∈ s, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoLocallyUniformlyOn F f atTop s := + Monotone.tendstoLocallyUniformlyOn_of_forall_tendsto (G := Gᵒᵈ) hF_cont hF_anti hf h_tendsto + +/-- **Dini's theorem** If `F n` is a monotone decreasing collection of continuous functions on a +compact space converging pointwise to a continuous function `f`, then `F n` converges uniformly +to `f`. -/ +lemma tendstoUniformly_of_forall_tendsto [CompactSpace α] (hF_cont : ∀ i, Continuous (F i)) + (hF_anti : Antitone F) (hf : Continuous f) (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoUniformly F f atTop := + Monotone.tendstoUniformly_of_forall_tendsto (G := Gᵒᵈ) hF_cont hF_anti hf h_tendsto + +/-- **Dini's theorem** If `F n` is a monotone decreasing collection of continuous functions on a +compact set `s` converging pointwise to a continuous `f`, then `F n` converges uniformly to `f`. -/ +lemma tendstoUniformlyOn_of_forall_tendsto {s : Set α} (hs : IsCompact s) + (hF_cont : ∀ i, ContinuousOn (F i) s) (hF_anti : ∀ x ∈ s, Antitone (F · x)) + (hf : ContinuousOn f s) (h_tendsto : ∀ x ∈ s, Tendsto (F · x) atTop (𝓝 (f x))) : + TendstoUniformlyOn F f atTop s := + Monotone.tendstoUniformlyOn_of_forall_tendsto (G := Gᵒᵈ) hs hF_cont hF_anti hf h_tendsto + +end Antitone + +end Unbundled + +namespace ContinuousMap + +variable {F : ι → C(α, G)} {f : C(α, G)} + +/-- **Dini's theorem** If `F n` is a monotone increasing collection of continuous functions +converging pointwise to a continuous function `f`, then `F n` converges to `f` in the +compact-open topology. -/ +lemma tendsto_of_monotone_of_pointwise (hF_mono : Monotone F) + (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + Tendsto F atTop (𝓝 f) := + tendsto_of_tendstoLocallyUniformly <| + hF_mono.tendstoLocallyUniformly_of_forall_tendsto (F · |>.continuous) f.continuous h_tendsto + +/-- **Dini's theorem** If `F n` is a monotone decreasing collection of continuous functions +converging pointwise to a continuous function `f`, then `F n` converges to `f` in the +compact-open topology. -/ +lemma tendsto_of_antitone_of_pointwise (hF_anti : Antitone F) + (h_tendsto : ∀ x, Tendsto (F · x) atTop (𝓝 (f x))) : + Tendsto F atTop (𝓝 f) := + tendsto_of_monotone_of_pointwise (G := Gᵒᵈ) hF_anti h_tendsto + +end ContinuousMap diff --git a/Mathlib/Topology/UniformSpace/HeineCantor.lean b/Mathlib/Topology/UniformSpace/HeineCantor.lean index d97593eba0566..166e33321e049 100644 --- a/Mathlib/Topology/UniformSpace/HeineCantor.lean +++ b/Mathlib/Topology/UniformSpace/HeineCantor.lean @@ -3,9 +3,9 @@ Copyright (c) 2020 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Yury Kudryashov -/ -import Mathlib.Topology.UniformSpace.Equicontinuity +import Mathlib.Topology.Algebra.Support import Mathlib.Topology.UniformSpace.Compact -import Mathlib.Topology.Support +import Mathlib.Topology.UniformSpace.Equicontinuity /-! # Compact separated uniform spaces diff --git a/Mathlib/Topology/UniformSpace/UniformConvergence.lean b/Mathlib/Topology/UniformSpace/UniformConvergence.lean index 48ea1c9d19316..d6bb495deea18 100644 --- a/Mathlib/Topology/UniformSpace/UniformConvergence.lean +++ b/Mathlib/Topology/UniformSpace/UniformConvergence.lean @@ -273,10 +273,11 @@ theorem TendstoUniformlyOnFilter.prod {ι' β' : Type*} [UniformSpace β'] {F' : (p ×ˢ q) p' := fun u hu => ((h.prod_map h') u hu).diag_of_prod_right -theorem TendstoUniformlyOn.prod {ι' β' : Type*} [UniformSpace β'] {F' : ι' → α → β'} {f' : α → β'} - {p' : Filter ι'} (h : TendstoUniformlyOn F f p s) (h' : TendstoUniformlyOn F' f' p' s) : +protected theorem TendstoUniformlyOn.prod {ι' β' : Type*} [UniformSpace β'] + {F' : ι' → α → β'} {f' : α → β'} {p' : Filter ι'} + (h : TendstoUniformlyOn F f p s) (h' : TendstoUniformlyOn F' f' p' s) : TendstoUniformlyOn (fun (i : ι × ι') a => (F i.1 a, F' i.2 a)) (fun a => (f a, f' a)) - (p.prod p') s := + (p ×ˢ p') s := (congr_arg _ s.inter_self).mp ((h.prod_map h').comp fun a => (a, a)) theorem TendstoUniformly.prod {ι' β' : Type*} [UniformSpace β'] {F' : ι' → α → β'} {f' : α → β'} @@ -333,8 +334,7 @@ theorem UniformContinuousOn.tendstoUniformlyOn [UniformSpace α] [UniformSpace set φ := fun q : α × β => ((x, q.2), q) rw [tendstoUniformlyOn_iff_tendsto] change Tendsto (Prod.map (↿F) ↿F ∘ φ) (𝓝[U] x ×ˢ 𝓟 V) (𝓤 γ) - simp only [nhdsWithin, SProd.sprod, Filter.prod, comap_inf, inf_assoc, comap_principal, - inf_principal] + simp only [nhdsWithin, Filter.prod_eq_inf, comap_inf, inf_assoc, comap_principal, inf_principal] 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] diff --git a/Mathlib/Util/DischargerAsTactic.lean b/Mathlib/Util/DischargerAsTactic.lean index b7662072b5f0a..cbac978463f1d 100644 --- a/Mathlib/Util/DischargerAsTactic.lean +++ b/Mathlib/Util/DischargerAsTactic.lean @@ -22,7 +22,7 @@ so that it can be passed as an argument to `simp (discharger := foo)`. This is inverse to `mkDischargeWrapper`. -/ def wrapSimpDischarger (dis : Simp.Discharge) : TacticM Unit := do let eS : Lean.Meta.Simp.State := {} - let eC : Lean.Meta.Simp.Context := {} + let eC : Lean.Meta.Simp.Context := ← Simp.mkContext {} let eM : Lean.Meta.Simp.Methods := {} let (some a, _) ← liftM <| StateRefT'.run (ReaderT.run (ReaderT.run (dis <| ← getMainTarget) eM.toMethodsRef) eC) eS | failure diff --git a/Mathlib/Util/IncludeStr.lean b/Mathlib/Util/IncludeStr.lean deleted file mode 100644 index 662a23839c5ff..0000000000000 --- a/Mathlib/Util/IncludeStr.lean +++ /dev/null @@ -1,22 +0,0 @@ -/- -Copyright (c) 2021 Henrik Böving. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Henrik Böving, Xubai Wang --/ -import Mathlib.Init - -/-! -# Defines the `include_str` macro. --/ - -namespace Mathlib.Util - -/-- A term macro that includes the content of a file, as a string. -/ -elab (name := includeStr) "include_str " str:str : term => do - let some str := str.1.isStrLit? | Lean.Elab.throwUnsupportedSyntax - let srcPath := System.FilePath.mk (← Lean.MonadLog.getFileName) - let some srcDir := srcPath.parent | throwError "{srcPath} not in a valid directory" - let path := srcDir / str - Lean.mkStrLit <$> IO.FS.readFile path - -end Mathlib.Util diff --git a/Mathlib/Util/Superscript.lean b/Mathlib/Util/Superscript.lean index 85d3b2fecae7f..e322df63fe38f 100644 --- a/Mathlib/Util/Superscript.lean +++ b/Mathlib/Util/Superscript.lean @@ -277,11 +277,7 @@ def subscript.parenthesizer := Superscript.scriptParser.parenthesizer ``subscrip def subscript.formatter := Superscript.scriptParser.formatter "subscript" .subscript ``subscript initialize - registerAlias `superscript ``superscript superscript - registerAliasCore Formatter.formatterAliasesRef `superscript superscript.formatter - registerAliasCore Parenthesizer.parenthesizerAliasesRef `superscript superscript.parenthesizer - registerAlias `subscript ``subscript subscript - registerAliasCore Formatter.formatterAliasesRef `subscript subscript.formatter - registerAliasCore Parenthesizer.parenthesizerAliasesRef `subscript subscript.parenthesizer + register_parser_alias superscript + register_parser_alias subscript end Mathlib.Tactic diff --git a/Mathlib/Util/TransImports.lean b/Mathlib/Util/TransImports.lean new file mode 100644 index 0000000000000..701b77fbf8bc3 --- /dev/null +++ b/Mathlib/Util/TransImports.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2024 Damiano Testa. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Damiano Testa +-/ + +import Mathlib.Init + +/-! # The `#trans_imports` command + +`#trans_imports` reports how many transitive imports the current module has. +The command takes an optional string input: `#trans_imports str` also shows the transitively +imported modules whose name begins with `str`. +-/ + +/-- +`#trans_imports` reports how many transitive imports the current module has. +The command takes an optional string input: `#trans_imports str` also shows the transitively +imported modules whose name begins with `str`. + +Mostly for the sake of tests, the command also takes an optional `at_most x` input: +if the number of imports does not exceed `x`, then the message involves `x`, rather than the +actual, possibly varying, number of imports. +-/ +syntax (name := transImportsStx) "#trans_imports" (ppSpace str)? (&" at_most " num)? : command + +open Lean in +@[inherit_doc transImportsStx] +elab_rules : command +| `(command| #trans_imports $(stx)? $[at_most $le:num]?) => do + let imports := (← getEnv).allImportedModuleNames + let currMod := if let mod@(.str _ _) := ← getMainModule then m!"'{mod}' has " else "" + let rest := match stx with + | none => m!"" + | some str => + let imps := imports.filterMap fun (i : Name) => + if i.toString.startsWith str.getString then some i else none + m!"\n\n{imps.size} starting with {str}:\n{imps.qsort (·.toString < ·.toString)}" + match le with + | none => logInfo m!"{currMod}{imports.size} transitive imports{rest}" + | some bd => + if imports.size ≤ bd.getNat then + logInfo m!"{currMod}at most {bd} transitive imports{rest}" + else + logWarningAt bd + m!"{currMod}{imports.size} transitive imports, exceeding the expected bound of {bd}{rest}" diff --git a/MathlibTest/CategoryTheory/ConcreteCategory/ModuleCat.lean b/MathlibTest/CategoryTheory/ConcreteCategory/ModuleCat.lean new file mode 100644 index 0000000000000..650d59aeef1ba --- /dev/null +++ b/MathlibTest/CategoryTheory/ConcreteCategory/ModuleCat.lean @@ -0,0 +1,53 @@ +import Mathlib.Algebra.Category.ModuleCat.Basic + +universe v u + +open CategoryTheory ModuleCat + +set_option maxHeartbeats 10000 +set_option synthInstance.maxHeartbeats 2000 + +variable (R : Type u) [CommRing R] + +/- We test if all the coercions and `map_add` lemmas trigger correctly. -/ + +example (X : Type v) [AddCommGroup X] [Module R X] : ⇑(𝟙 (of R X)) = id := by simp + +example {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] (f : X →ₗ[R] Y) : + ⇑(ModuleCat.ofHom f) = ⇑f := by simp + +example {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] (f : X →ₗ[R] Y) + (x : X) : (ModuleCat.ofHom f) x = f x := by simp + +example {X Y Z : ModuleCat R} (f : X ⟶ Y) (g : Y ⟶ Z) : ⇑(f ≫ g) = ⇑g ∘ ⇑f := by simp + +example {X Y Z : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] [Ring Z] + [Algebra R Z] (f : X →ₗ[R] Y) (g : Y →ₗ[R] Z) : + ⇑(ModuleCat.ofHom f ≫ ModuleCat.ofHom g) = g ∘ f := by simp + +example {X Y : Type v} [AddCommGroup X] [Module R X] [AddCommGroup Y] [Module R Y] {Z : ModuleCat R} + (f : X →ₗ[R] Y) (g : of R Y ⟶ Z) : + ⇑(ModuleCat.ofHom f ≫ g) = g ∘ f := by simp + +example {X Y : ModuleCat R} {Z : Type v} [Ring Z] [Algebra R Z] (f : X ⟶ Y) (g : Y ⟶ of R Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {Y Z : ModuleCat R} {X : Type v} [AddCommGroup X] [Module R X] (f : of R X ⟶ Y) (g : Y ⟶ Z) : + ⇑(f ≫ g) = g ∘ f := by simp + +example {X Y Z : ModuleCat R} (f : X ⟶ Y) (g : Y ⟶ Z) (x : X) : (f ≫ g) x = g (f x) := by simp + +example {X Y : ModuleCat R} (e : X ≅ Y) (x : X) : e.inv (e.hom x) = x := by simp + +example {X Y : ModuleCat R} (e : X ≅ Y) (y : Y) : e.hom (e.inv y) = y := by simp + +example (X : ModuleCat R) : ⇑(𝟙 X) = id := by simp + +example {M N : ModuleCat.{v} R} (f : M ⟶ N) (x y : M) : f (x + y) = f x + f y := by + simp + +example {M N : ModuleCat.{v} R} (f : M ⟶ N) : f 0 = 0 := by + simp + +example {M N : ModuleCat.{v} R} (f : M ⟶ N) (r : R) (m : M) : f (r • m) = r • f m := by + simp diff --git a/MathlibTest/EuclideanSpace.lean b/MathlibTest/EuclideanSpace.lean new file mode 100644 index 0000000000000..662b91d2a0251 --- /dev/null +++ b/MathlibTest/EuclideanSpace.lean @@ -0,0 +1,33 @@ +import Mathlib.Analysis.InnerProductSpace.PiL2 + +#guard_expr !₂[] = (WithLp.equiv 2 (∀ _ : Fin 0, _)).symm ![] +#guard_expr !₂[1, 2, 3] = (WithLp.equiv 2 (∀ _ : Fin 3, ℕ)).symm ![1, 2, 3] +#guard_expr !₁[1, 2, (3 : ℝ)] = (WithLp.equiv 1 (∀ _ : Fin 3, ℝ)).symm ![1, 2, 3] + +section delaborator + +/-- info: !₂[1, 2, 3] : WithLp 2 (Fin 3 → ℕ) -/ +#guard_msgs in +#check !₂[1, 2, 3] + +set_option pp.mvars false in +/-- info: !₀[] : WithLp 0 (Fin 0 → ?_) -/ +#guard_msgs in +#check !₀[] + +section var +variable {p : ENNReal} +/-- info: (WithLp.equiv p (Fin 3 → ℕ)).symm ![1, 2, 3] : WithLp p (Fin 3 → ℕ) -/ +#guard_msgs in#check !ₚ[1, 2, 3] +end var + +section tombstoned_var +/- Here the `p` in the subscript is shadowed by a later p; so even if we do +make the delaborator less conservative, it should not fire here since `✝` cannot +be subscripted. -/ +variable {p : ENNReal} {x} (hx : x = !ₚ[1, 2, 3]) (p : True) +/-- info: hx : x = (WithLp.equiv p✝ (Fin 3 → ℕ)).symm ![1, 2, 3] -/ +#guard_msgs in #check hx +end tombstoned_var + +end delaborator diff --git a/MathlibTest/Expr.lean b/MathlibTest/Expr.lean index 1e4b9fd11388d..84efba4ecb2f9 100644 --- a/MathlibTest/Expr.lean +++ b/MathlibTest/Expr.lean @@ -13,7 +13,7 @@ def reorderLastArguments : Expr → Expr := Expr.replaceRec fun r e ↦ let n := e.getAppNumArgs if n ≥ 2 then - mkAppN e.getAppFn <| e.getAppArgs.map r |>.swap! (n - 1) (n - 2) + mkAppN e.getAppFn <| e.getAppArgs.map r |>.swapIfInBounds (n - 1) (n - 2) else none diff --git a/MathlibTest/NthRewrite.lean b/MathlibTest/NthRewrite.lean index 287039007dce6..3b82ffdb5998a 100644 --- a/MathlibTest/NthRewrite.lean +++ b/MathlibTest/NthRewrite.lean @@ -16,7 +16,7 @@ example [AddZeroClass G] {a : G} : a + a = a + (a + 0) := by structure F where (a : ℕ) - (v : Vector ℕ a) + (v : Mathlib.Vector ℕ a) (p : v.val = []) example (f : F) : f.v.val = [] := by diff --git a/MathlibTest/Simps.lean b/MathlibTest/Simps.lean index 8def1aa96d6ef..2c3e0d2f69483 100644 --- a/MathlibTest/Simps.lean +++ b/MathlibTest/Simps.lean @@ -1203,7 +1203,7 @@ structure Foo where @[simps field field_2 field_9_fst] def myFoo : Foo := ⟨1, ⟨1, 1⟩, 1⟩ -structure Prod (X Y : Type _) extends Prod X Y +structure Prod (X Y : Type _) extends _root_.Prod X Y structure Prod2 (X Y : Type _) extends Prod X Y diff --git a/MathlibTest/TransImports.lean b/MathlibTest/TransImports.lean new file mode 100644 index 0000000000000..964187009033d --- /dev/null +++ b/MathlibTest/TransImports.lean @@ -0,0 +1,10 @@ +import Mathlib.Util.TransImports + +/-- +info: 'MathlibTest.TransImports' has at most 500 transitive imports + +3 starting with "Lean.Elab.I": +[Lean.Elab.InfoTree, Lean.Elab.InfoTree.Main, Lean.Elab.InfoTree.Types] +-/ +#guard_msgs in +#trans_imports "Lean.Elab.I" at_most 500 diff --git a/MathlibTest/cc.lean b/MathlibTest/cc.lean index 4d0f3eb630b40..26e0d6ac83f4d 100644 --- a/MathlibTest/cc.lean +++ b/MathlibTest/cc.lean @@ -220,17 +220,21 @@ universe u open Mathlib -axiom app : {α : Type u} → {n m : Nat} → Vector α m → Vector α n → Vector α (m + n) +axiom app : {α : Type u} → {n m : Nat} → + Mathlib.Vector α m → Mathlib.Vector α n → Mathlib.Vector α (m + n) -example (n1 n2 n3 : Nat) (v1 w1 : Vector Nat n1) (w1' : Vector Nat n3) (v2 w2 : Vector Nat n2) : +example (n1 n2 n3 : Nat) + (v1 w1 : Mathlib.Vector Nat n1) (w1' : Mathlib.Vector Nat n3) (v2 w2 : Mathlib.Vector Nat n2) : n1 = n3 → v1 = w1 → HEq w1 w1' → v2 = w2 → HEq (app v1 v2) (app w1' w2) := by cc -example (n1 n2 n3 : Nat) (v1 w1 : Vector Nat n1) (w1' : Vector Nat n3) (v2 w2 : Vector Nat n2) : +example (n1 n2 n3 : Nat) + (v1 w1 : Mathlib.Vector Nat n1) (w1' : Mathlib.Vector Nat n3) (v2 w2 : Mathlib.Vector Nat n2) : HEq n1 n3 → v1 = w1 → HEq w1 w1' → HEq v2 w2 → HEq (app v1 v2) (app w1' w2) := by cc -example (n1 n2 n3 : Nat) (v1 w1 v : Vector Nat n1) (w1' : Vector Nat n3) (v2 w2 w : Vector Nat n2) : +example (n1 n2 n3 : Nat) + (v1 w1 v : Mathlib.Vector Nat n1) (w1' : Mathlib.Vector Nat n3) (v2 w2 w : Mathlib.Vector Nat n2) : HEq n1 n3 → v1 = w1 → HEq w1 w1' → HEq v2 w2 → HEq (app w1' w2) (app v w) → app v1 v2 = app v w := by cc diff --git a/MathlibTest/instance_diamonds.lean b/MathlibTest/instance_diamonds.lean index 5696071a4fb62..48cf79849a3b7 100644 --- a/MathlibTest/instance_diamonds.lean +++ b/MathlibTest/instance_diamonds.lean @@ -3,13 +3,14 @@ Copyright (c) 2021 Eric Wieser. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Eric Wieser -/ +import Mathlib.Algebra.EuclideanDomain.Field import Mathlib.Algebra.GroupWithZero.Action.Prod import Mathlib.Algebra.GroupWithZero.Action.Units import Mathlib.Algebra.Module.Pi import Mathlib.Algebra.Polynomial.Basic import Mathlib.Data.Complex.Module import Mathlib.Data.ZMod.Basic -import Mathlib.RingTheory.Algebraic +import Mathlib.RingTheory.Algebraic.Pi import Mathlib.RingTheory.TensorProduct.Basic /-! # Tests that instances do not form diamonds -/ @@ -225,8 +226,8 @@ end Polynomial section Subtype -- this diamond is the reason that `Fintype.toLocallyFiniteOrder` is not an instance -example {α} [Preorder α] [LocallyFiniteOrder α] [Fintype α] [@DecidableRel α (· < ·)] - [@DecidableRel α (· ≤ ·)] (p : α → Prop) [DecidablePred p] : +example {α} [Preorder α] [LocallyFiniteOrder α] [Fintype α] [DecidableRel (α := α) (· < ·)] + [DecidableRel (α := α) (· ≤ ·)] (p : α → Prop) [DecidablePred p] : Subtype.instLocallyFiniteOrder p = Fintype.toLocallyFiniteOrder := by fail_if_success rfl exact Subsingleton.elim _ _ diff --git a/MathlibTest/norm_num_ext.lean b/MathlibTest/norm_num_ext.lean index de2675f268b14..0e78dab0f080c 100644 --- a/MathlibTest/norm_num_ext.lean +++ b/MathlibTest/norm_num_ext.lean @@ -10,6 +10,7 @@ import Mathlib.Tactic.NormNum.DivMod import Mathlib.Tactic.NormNum.NatFib import Mathlib.Tactic.NormNum.NatSqrt import Mathlib.Tactic.NormNum.Prime +import Mathlib.Data.Rat.Floor import Mathlib.Tactic.NormNum.LegendreSymbol import Mathlib.Tactic.NormNum.Pow @@ -400,6 +401,11 @@ example : ⌊(2 : R)⌋ = 2 := by norm_num example : ⌊(15 / 16 : K)⌋ + 1 = 1 := by norm_num example : ⌊(-15 / 16 : K)⌋ + 1 = 0 := by norm_num +example : ⌈(-1 : R)⌉ = -1 := by norm_num +example : ⌈(2 : R)⌉ = 2 := by norm_num +example : ⌈(15 / 16 : K)⌉ + 1 = 2 := by norm_num +example : ⌈(-15 / 16 : K)⌉ + 1 = 1 := by norm_num + end floor section jacobi diff --git a/README.md b/README.md index 6e5a49dbeafd5..5dd59489b323e 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ For a list containing more detailed information, see https://leanprover-communit * Patrick Massot (@patrickmassot): documentation, topology, geometry * Bhavik Mehta (@b-mehta): category theory, combinatorics * Kyle Miller (@kmill): combinatorics, tactics, metaprogramming -* Kim Morrison (@semorrison): category theory, tactics +* Kim Morrison (@kim-em): category theory, tactics * Oliver Nash (@ocfnash): algebra, geometry, topology * Joël Riou (@joelriou): category theory, homology, algebraic geometry * Damiano Testa (@adomani): algebra, algebraic geometry, number theory, tactics diff --git a/docs/1000.yaml b/docs/1000.yaml new file mode 100644 index 0000000000000..8126486a00af9 --- /dev/null +++ b/docs/1000.yaml @@ -0,0 +1,3612 @@ +# This file tracks the formalisation status of theorems from the experimental +# 1000+ theorems project (https://1000-plus.github.io/). +# This file and associated infrastructure are work in progress. +# +# Current TODOs/unresolved questions: +# - should this file include further metadata, such as repository links, author names or dates? +# - add infrastructure for updating the information upstream when formalisations are added +# - perhaps add a wikidata version of the stacks tag, and generate this file automatically +# (can this handle formalisation of *statements* also?) +# - complete the information which theorems are already formalised + +Q11518: + title: Pythagorean theorem + +Q12524: + title: Schwenk's theorem + +Q26708: + title: Binomial theorem + +Q32182: + title: Balinski's theorem + +Q33481: + title: Arrow's impossibility theorem + +Q98831: + title: Multiplication theorem + +Q117553: + title: Modigliani–Miller theorem + +Q119450: + title: Brianchon's theorem + +Q132427: + title: Rademacher's theorem + +Q132469: + title: Fermat's Last Theorem + +Q137164: + title: Besicovitch covering theorem + +Q154210: + title: CPCTC + +Q164262: + title: Lebesgue covering dimension + +Q172298: + title: Lasker–Noether theorem + +Q174955: + title: Mihăilescu's theorem + +Q179208: + title: Cayley's theorem + +Q179467: + title: Fourier theorem + +Q179692: + title: Independence of the axiom of choice + +Q180345X: + title: Integral root theorem + +Q180345: + title: Rational root theorem + +Q182505: + title: Bayes' theorem + +Q184410: + title: Four color theorem + +Q188295: + title: Fermat's little theorem + +Q188745: + title: Classification of Platonic solids + +Q189136: + title: Mean value theorem + +Q190026: + title: Ford's theorem + +Q190391X: + title: Lyapunov's central limit theorem + +Q190391: + title: Central limit theorem + +Q190556: + title: De Moivre's theorem + +Q191693: + title: Lebesgue's decomposition theorem + +Q192760: + title: Fundamental theorem of algebra + +Q193286: + title: Rolle's theorem + +Q193878: + title: Chinese remainder theorem + +Q193882: + title: Menelaus's theorem + +Q193910: + title: Euler's theorem + +Q194919: + title: Inverse eigenvalues theorem + +Q195133: + title: Wigner–Eckart theorem + +Q200787: + title: Gödel's incompleteness theorem + +Q203565: + title: Solutions of a general cubic equation + +Q204884: + title: Löb's theorem + +Q205966: + title: Critical line theorem + +Q207014: + title: Independence of the parallel postulate + +Q207244: + title: Sela's theorem + +Q208416: + title: Independence of the continuum hypothesis + url: https://github.com/flypitch/flypitch + identifiers: + - independence_of_CH + author: Floris van Doorn and Jesse Michael Han + date: 2019-09-17 + +Q208756: + title: Castelnuovo theorem + +Q211981: + title: Hartman–Grobman theorem + +Q213603: + title: Ceva's theorem + +Q220680: + title: Banach fixed-point theorem + +Q225973: + title: Ore's theorem + +Q226014: + title: Poincaré recurrence theorem + +Q230848: + title: Lamé’s theorem + +Q240950: + title: Faltings's theorem + +Q241868: + title: Thévenin's theorem + +Q242045: + title: Monotone class theorem + +Q245098: + title: Intermediate value theorem + +Q245098X: + title: Bolzano's theorem + +Q245902: + title: Riesz–Thorin theorem + +Q248931: + title: Poincaré–Bendixson theorem + +Q253214: + title: Heine–Borel theorem + +Q255996: + title: Equipartition theorem + +Q256303: + title: Lax–Richtmyer theorem + +Q257387: + title: Vitali theorem + +Q258374: + title: Carathéodory's theorem + +Q260928: + title: Jordan curve theorem + +Q266291: + title: Bloch's theorem + +Q268031: + title: Abel's binomial theorem + +Q268132: + title: Gauss–Wantzel theorem + +Q273037: + title: Bondy–Chvátal theorem + +Q276082: + title: Wilson's theorem + +Q280116: + title: Odd number theorem + +Q282331: + title: Addition theorem + +Q282649: + title: Pentagonal number theorem + +Q283690: + title: Arrival theorem + +Q284960: + title: Mordell–Weil theorem + +Q285719: + title: Thales's theorem + +Q287347: + title: Gradient theorem + +Q288465: + title: Orbit-stabilizer theorem + +Q303402: + title: Rank–nullity theorem + +Q318767: + title: Abel's theorem + +Q321237: + title: Green's theorem + +Q332465: + title: Absolute convergence theorem + +Q338886: + title: Divergence theorem + +Q339495: + title: Symphonic theorem + +Q356895: + title: Adiabatic theorem + +Q357192: + title: Holland's schema theorem + +Q357858: + title: Freyd's adjoint functor theorem + +Q371685: + title: Kraft–McMillan theorem + +Q372037: + title: Seifert–van Kampen theorem + +Q376166: + title: Cut-elimination theorem + +Q377047: + title: Butterfly theorem + +Q377276: + title: Cook's theorem + +Q379048: + title: Riemann–Roch theorem + +Q380576: + title: Measurable Riemann mapping theorem + +Q383238: + title: Hartogs's extension theorem + +Q384142: + title: Herbrand–Ribet theorem + +Q386292: + title: Prime number theorem + +Q388525: + title: Bell's theorem + +Q401319: + title: Puiseux's theorem + +Q401905: + title: Skorokhod's representation theorem + +Q420714: + title: Akra–Bazzi theorem + +Q422187: + title: Myhill–Nerode theorem + +Q425432: + title: Laurent expansion theorem + +Q428134: + title: Gauss–Markov theorem + +Q459547: + title: Ptolemy's theorem + +Q467205: + title: Fundamental theorems of welfare economics + +Q467756: + title: Stokes's theorem + +Q468391: + title: Bolzano–Weierstrass theorem + +Q470877: + title: Stirling's theorem + +Q472883: + title: Quadratic reciprocity theorem + +Q474881: + title: Cantor's theorem + +Q476776: + title: Solutions of a general quartic equation + +Q487132: + title: Infinite monkey theorem + +Q488541: + title: Fisher separation theorem + +Q495412: + title: Jordan–Schönflies theorem + +Q504843: + title: Mycielski's theorem + +Q505798: + title: Lagrange's theorem + +Q510197: + title: Tutte theorem + +Q512897: + title: Brooks's theorem + +Q523832: + title: Carathéodory–Jacobi–Lie theorem + +Q523876: + title: Spin–statistics theorem + +Q528955: + title: Kochen–Specker theorem + +Q528987: + title: Von Neumann bicommutant theorem + +Q530152: + title: Picard–Lindelöf theorem + +Q535366: + title: Montel's theorem + +Q536640: + title: Hall's marriage theorem + +Q537618: + title: Banach–Alaoglu theorem + +Q544292: + title: Lagrange inversion theorem + +Q544369: + title: Glivenko–Cantelli theorem + +Q550402: + title: Dirichlet's theorem on arithmetic progressions + +Q552367: + title: Berge's theorem + +Q567843: + title: Hahn–Mazurkiewicz theorem + +Q570779: + title: Vieta's formulas + +Q574902: + title: Tarski's indefinability theorem + +Q576478: + title: Liouville's theorem + +Q578555: + title: Noether's theorem + +Q579515: + title: Rao–Blackwell theorem + +Q583147: + title: Sard's theorem + +Q586051: + title: Haag–Łopuszański–Sohnius theorem + +Q587081: + title: Kolmogorov–Arnold–Moser theorem + +Q588218: + title: Koebe 1/4 theorem + +Q594571: + title: Van Aubel's theorem + +Q595466: + title: Dini's theorem + +Q599876: + title: Cochran's theorem + +Q608294: + title: Max flow min cut theorem + +Q609612: + title: Knaster–Tarski theorem + +Q612021: + title: Gibbard–Satterthwaite theorem + +Q617417: + title: Isoperimetric theorem + +Q619985: + title: Multinomial theorem + +Q620602: + title: Virial theorem + +Q631561: + title: Closed range theorem + +Q632546X: + title: Sylvester's theorem + +Q632546: + title: Bertrand's postulate + +Q637418: + title: Napoleon's theorem + +Q642620: + title: Krein–Milman theorem + +Q643513: + title: Riesz–Fischer theorem + +Q643826: + title: Slutsky's theorem + +Q646523: + title: Pick's theorem + +Q649469: + title: Modularity theorem + +Q649977: + title: Shirshov–Cohn theorem + +Q650738: + title: Folk theorem + +Q651593: + title: Norton's theorem + +Q656176: + title: Schauder fixed-point theorem + +Q656198: + title: Maschke's theorem + +Q656645: + title: Hilbert's basis theorem + +Q656772: + title: Cayley–Hamilton theorem + +Q657469: + title: Lefschetz fixed-point theorem + +Q657469X: + title: Lefschetz–Hopf theorem + +Q657482: + title: Abel–Ruffini theorem + +Q657903: + title: Hilbert–Waring theorem + +Q660799: + title: Darboux's theorem + +Q670235: + title: Fundamental theorem of arithmetic + +Q671663: + title: Coleman–Mandula theorem + +Q676413: + title: Dandelin's theorem + +Q679800: + title: Nyquist–Shannon sampling theorem + +Q681406: + title: Euler's rotation theorem + +Q685437: + title: Titchmarsh theorem + +Q693083: + title: Soundness theorem + +Q716171: + title: Erdős–Ginzburg–Ziv theorem + +Q718875: + title: Erdős–Ko–Rado theorem + +Q719966: + title: Toda's theorem + +Q720469: + title: Chevalley–Warning theorem + +Q721695: + title: Szemerédi–Trotter theorem + +Q727102: + title: Fermat's theorem (stationary points) + +Q729359: + title: Hadamard three-circle theorem + +Q730222: + title: Ham sandwich theorem + +Q733081: + title: Impossibility of angle trisection + +Q737851: + title: Banach–Tarski theorem + +Q737892: + title: Bendixson–Dulac theorem + +Q739403: + title: Stewart's theorem + +Q740093: + title: Peano existence theorem + +Q742833: + title: Gauss–Bonnet theorem + +Q744440: + title: Immerman–Szelepcsényi theorem + +Q748233: + title: Sylvester–Gallai theorem + +Q751120: + title: Thue–Siegel–Roth theorem + +Q752375: + title: Extreme value theorem + +Q755986: + title: Atiyah–Bott fixed-point theorem + +Q755991: + title: Atiyah–Singer index theorem + +Q756946: + title: Lagrange's four-square theorem + +Q764287: + title: Van der Waerden's theorem + +Q765987: + title: Heine–Cantor theorem + +Q766722: + title: Liouville's theorem + +Q776578: + title: Artin–Wedderburn theorem + +Q777924: + title: Tijdeman's theorem + +Q779220: + title: Hilbert's syzygy theorem + +Q780763: + title: 15 and 290 theorems + +Q784049: + title: Blaschke selection theorem + +Q790236: + title: Baranyai's theorem + +Q791258: + title: Basu's theorem + +Q791663: + title: Beatty's theorem + +Q794269: + title: Betti's theorem + +Q810431: + title: Basel problem + +Q828284: + title: Parallel axis theorem + +Q830124: + title: Girsanov's theorem + +Q830513: + title: Residue theorem + +Q834025: + title: Cauchy integral theorem + +Q834211: + title: Wallace–Bolyai–Gerwien theorem + +Q837506: + title: Theorem on friends and strangers + +Q837551: + title: Frobenius theorem + +Q841893: + title: Desargues's theorem + +Q842953: + title: Lebesgue's density theorem + +Q844612: + title: Brun's theorem + +Q845088: + title: Pappus's centroid theorem + +Q846840: + title: Erdős–Kac theorem + +Q848092: + title: Borsuk–Ulam theorem + +Q848375: + title: Implicit function theorem + +Q848810: + title: Kronecker's theorem + +Q850495: + title: Wick's theorem + +Q851166: + title: Pappus's hexagon theorem + +Q852183: + title: Viviani's theorem + +Q852973: + title: Euler's polyhedron theorem + +Q853067: + title: Solutions to Pell's equation + +Q856032: + title: CAP theorem + +Q856158: + title: Midy's theorem + +Q857089: + title: de Branges's theorem + +Q858978: + title: Castigliano's first and second theorems + +Q859122: + title: Cauchy–Hadamard theorem + +Q865665: + title: Birkhoff's theorem + +Q866116: + title: Hahn–Banach theorem + +Q867141: + title: Ehresmann's theorem + +Q867839: + title: Rosser's theorem + +Q869647: + title: Szpilrajn extension theorem + +Q872088: + title: Boolean prime ideal theorem + +Q877489: + title: Apollonius's theorem + +Q890875: + title: Bohr–van Leeuwen theorem + +Q897769: + title: König's theorem + +Q899002: + title: Pascal's theorem + +Q899853: + title: H-theorem + +Q900831: + title: Fluctuation theorem + +Q902052: + title: Gödel's completeness theorem + +Q902618: + title: Floquet's theorem + +Q906809: + title: Hellmann–Feynman theorem + +Q909517: + title: Feit–Thompson theorem + +Q913447: + title: Morley's trisector theorem + +Q913849: + title: Minimax theorem + +Q914517: + title: Fermat's theorem on sums of two squares + +Q915474: + title: Robin's theorem + +Q918099: + title: Ramsey's theorem + +Q922012: + title: Green–Tao theorem + +Q922367: + title: Master theorem (analysis of algorithms) + +Q925224: + title: Sonnenschein–Mantel–Debreu Theorem + +Q925854: + title: Angle bisector theorem + +Q927051: + title: Riemann mapping theorem + +Q928813: + title: Menger's theorem + +Q929547: + title: Myers theorem + +Q931001: + title: Inverse function theorem + +Q931001X: + title: Constant rank theorem + +Q931404: + title: Bertrand–Diquet–Puiseux theorem + +Q939927: + title: Stone–Weierstrass theorem + decl: ContinuousMap.subalgebra_topologicalClosure_eq_top_of_separatesPoints + author: Scott Morrison and Heather Macbeth + date: 2021-05-01 + +Q942046: + title: Schwarz–Ahlfors–Pick theorem + +Q943246: + title: Wedderburn's little theorem + +Q944297: + title: Open mapping theorem + +Q948664: + title: Kneser's theorem + +Q951327: + title: Pasch's theorem + +Q953062: + title: Reynolds transport theorem + +Q954210: + title: Savitch's theorem + +Q965294: + title: Thabit ibn Qurra's theorem + +Q966837: + title: Cramér–Wold theorem + +Q967972: + title: Open mapping theorem + +Q973359: + title: Rado's theorem + +Q974405: + title: Hille–Yosida theorem + +Q976033: + title: Gelfond–Schneider theorem + +Q976607: + title: Erdős–Szekeres theorem + +Q977912: + title: Stolper–Samuelson theorem + +Q978688: + title: Gershgorin circle theorem + +Q985009: + title: Helmholtz's theorems + +Q994401: + title: Four-vertex theorem + +Q995926: + title: Perpendicular axis theorem + +Q999783: + title: Buckingham π theorem + +Q1008566: + title: Gauss–Lucas theorem + +Q1032886: + title: Hales–Jewett theorem + +Q1033910: + title: Cantor–Bernstein–Schroeder theorem + +Q1037559: + title: Pólya enumeration theorem + +Q1038716: + title: Identity theorem + +Q1046232: + title: Szemerédi's theorem + +Q1047749: + title: Turán's theorem + +Q1048589: + title: Hohenberg–Kohn theorems + +Q1048874: + title: Gauss's Theorema Egregium + +Q1050037: + title: Coase theorem + +Q1050203: + title: Cantor's intersection theorem + +Q1050932: + title: Hartogs's theorem + +Q1051404: + title: Cesàro's theorem + +Q1052021: + title: Craig's interpolation theorem + +Q1052678: + title: Baire category theorem + +Q1052752: + title: Stolz–Cesàro theorem + +Q1054106: + title: Cox's theorem + +Q1056283: + title: May's theorem + +Q1057919: + title: Sylow theorems + +Q1058662: + title: Darboux's theorem + +Q1059151: + title: FWL theorem + +Q1064471: + title: Earnshaw's theorem + +Q1065257: + title: Squeeze theorem + +Q1065966: + title: Isomorphism theorem + +Q1067156: + title: Dominated convergence theorem + +Q1067156X: + title: Bounded convergence theorem + +Q1068085: + title: Closed graph theorem + +Q1068283: + title: Löwenheim–Skolem theorem + +Q1068385: + title: Clairaut's theorem + +Q1068976: + title: Hilbert's Nullstellensatz + +Q1075398: + title: Jung's theorem + +Q1076274: + title: Choquet–Bishop–de Leeuw theorem + +Q1077462: + title: König's theorem + +Q1077741: + title: Hairy ball theorem + +Q1082910: + title: Euler's partition theorem + +Q1095330: + title: Apéry's theorem + +Q1097021: + title: Minkowski's theorem + +Q1103054: + title: Lions–Lax–Milgram theorem + +Q1119094: + title: Paley–Wiener theorem + +Q1121027: + title: Krylov–Bogolyubov theorem + +Q1125462: + title: Dinostratus' theorem + +Q1129636: + title: Lehmann–Scheffé theorem + +Q1130846: + title: Ladner's theorem + +Q1131601: + title: Sklar's theorem + +Q1132952: + title: Euler's theorem on homogeneous functions + +Q1134296: + title: Supporting hyperplane theorem + +Q1134776: + title: Dilworth's theorem + +Q1135706: + title: Harnack's theorem + +Q1136043: + title: Hurwitz's theorem + +Q1136262: + title: Optical theorem + +Q1137014: + title: Tychonoff's theorem + +Q1137206: + title: Taylor's theorem + +Q1139041: + title: Cauchy's theorem + +Q1139430: + title: Hurwitz's theorem + +Q1139524: + title: Rationality theorem + +Q1140119: + title: Morera's theorem + +Q1140200: + title: PCP theorem + +Q1141747: + title: Carnot's theorem + +Q1143540: + title: Heckscher–Ohlin theorem + +Q1144897: + title: Brouwer fixed-point theorem + +Q1146791: + title: Fermat polygonal number theorem + +Q1148215: + title: Mitchell's embedding theorem + +Q1149022: + title: Fubini's theorem + +Q1149185X: + title: Kirby–Paris theorem + +Q1149185: + title: Goodstein's theorem + +Q1149458: + title: Compactness theorem + +Q1149522: + title: Lami's theorem + +Q1152521: + title: Mohr–Mascheroni theorem + +Q1153441: + title: Goldstone's theorem + +Q1153584: + title: Monotone convergence theorem + +Q1166774: + title: Stone's representation theorem for Boolean algebras + +Q1177508: + title: Rédei's theorem + +Q1179446: + title: De Rham's theorem + +Q1182249: + title: Deduction theorem + +Q1186134: + title: Poncelet–Steiner theorem + +Q1186808: + title: Lucas's theorem + +Q1187646: + title: Fundamental theorem on homomorphisms + +Q1188048: + title: Barbier's theorem + +Q1188392: + title: Zeckendorf's theorem + +Q1188504: + title: Pitman–Koopman–Darmois theorem + +Q1191319: + title: Radon–Nikodym theorem + +Q1191709: + title: Egorov's theorem + +Q1191862: + title: Rouché's theorem + +Q1194053: + title: Metrization theorems + +Q1196538: + title: Descartes's theorem + +Q1196729: + title: Mertens's theorems + +Q1202608: + title: De Gua's theorem + +Q1209546: + title: Kaplansky density theorem + +Q1217677: + title: Fundamental theorem of calculus + +Q1227061: + title: Khinchin's theorem + +Q1227702: + title: Dirichlet's unit theorem + +Q1227703: + title: Dirichlet's approximation theorem + +Q1242398: + title: Doob decomposition theorem + +Q1243340: + title: Birkhoff–Von Neumann theorem + +Q1249069: + title: Richardson's theorem + +Q1259814: + title: Nielsen–Schreier theorem + +Q1276318: + title: Schwartz kernel theorem + +Q1305766: + title: Poincaré–Hopf theorem + +Q1306092: + title: Nash embedding theorem + +Q1306095: + title: Whitney embedding theorem + +Q1307676: + title: Künneth theorem + +Q1308502: + title: Church–Rosser theorem + +Q1315949: + title: Mittag-Leffler's theorem + +Q1317350: + title: Chen's theorem + +Q1317367: + title: Japanese theorem for concyclic polygons + +Q1322892: + title: Dirac's theorems + +Q1330788: + title: Weierstrass factorization theorem + +Q1340623: + title: Classification of finite simple groups + +Q1346677: + title: Tietze extension theorem + +Q1347094: + title: Alternate Interior Angles Theorem + +Q1348736: + title: Rybczynski theorem + +Q1349282: + title: Eilenberg–Zilber theorem + +Q1357684: + title: Riesz representation theorem + +Q1361031: + title: Frobenius theorem + +Q1361393: + title: Luzin's theorem + +Q1366581: + title: Erdős–Rado theorem + +Q1369453: + title: Kronecker–Weber theorem + +Q1370316: + title: Casey's theorem + +Q1376515: + title: No-hair theorem + +Q1396592: + title: Franel–Landau theorem + +Q1420905: + title: Hilbert's theorem 90 + +Q1422083: + title: Ryll-Nardzewski fixed-point theorem + +Q1423818: + title: Euler's theorem in geometry + +Q1424481: + title: Frucht's theorem + +Q1425077: + title: Spectral theorem + +Q1425308: + title: Brahmagupta theorem + +Q1425529: + title: Chebotarev's density theorem + +Q1426292: + title: Banach–Steinhaus theorem + +Q1434158: + title: Fluctuation dissipation theorem + +Q1434805: + title: Max Noether's theorem + +Q1443036: + title: Parseval's theorem + +Q1452678: + title: Penrose–Hawking singularity theorems + +Q1455794: + title: Freudenthal suspension theorem + +Q1457052: + title: Well-ordering theorem + +Q1471282: + title: Radon's theorem + +Q1472120: + title: Hellinger–Toeplitz theorem + +Q1477053: + title: Arzelà–Ascoli theorem + +Q1505529: + title: Runge's theorem + +Q1506253: + title: Euclid's theorem + +Q1529941: + title: Peter–Weyl theorem + +Q1530275: + title: Dunford–Pettis theorem + +Q1535225: + title: Łoś' theorem + +Q1542114: + title: Bézout's theorem + +Q1543149: + title: Sokhatsky–Weierstrass theorem + +Q1547975: + title: Mermin–Wagner theorem + +Q1551745: + title: Binomial inverse theorem + +Q1555342: + title: Reeh–Schlieder theorem + +Q1564541: + title: Perron–Frobenius theorem + +Q1566341: + title: Hindman's theorem + +Q1566372: + title: Haag's theorem + +Q1568612: + title: Marden's theorem + +Q1568811: + title: Hahn decomposition theorem + +Q1572474: + title: Lindemann–Weierstrass theorem + +Q1576235: + title: Lochs's theorem + +Q1602819: + title: Lumer–Phillips theorem + +Q1614464: + title: Cauchy–Kowalevski theorem + +Q1621180: + title: Orlicz–Pettis theorem + +Q1630588: + title: Hurwitz's theorem + +Q1631749: + title: Lester's theorem + +Q1631992: + title: Steiner–Lehmus theorem + +Q1632301: + title: Sturm's theorem + +Q1632433: + title: Helly's theorem + +Q1637085: + title: Poynting's theorem + +Q1660147: + title: Mazur–Ulam theorem + +Q1668861: + title: Picard theorem + +Q1683356: + title: Japanese theorem for concyclic quadrilaterals + +Q1687147: + title: Sprague–Grundy theorem + +Q1694565: + title: Vinogradov's theorem + +Q1699024: + title: John ellipsoid + +Q1704878: + title: Appell–Humbert theorem + +Q1716166: + title: Mercer's theorem + +Q1720410: + title: Hjelmslev's theorem + +Q1724049: + title: Wolstenholme's theorem + +Q1727461: + title: Intersecting secants theorem + +Q1739994: + title: Brauer–Suzuki theorem + +Q1751105: + title: Blum's speedup theorem + +Q1751823: + title: No-cloning theorem + +Q1752516: + title: Riemann series theorem + +Q1752621: + title: Sylvester's law of inertia + +Q1752988: + title: Kutta–Joukowski theorem + +Q1756194: + title: Shannon–Hartley theorem + +Q1765521: + title: Doob's martingale convergence theorems + +Q1766814: + title: Smn theorem + +Q1785610: + title: Poncelet's closure theorem + +Q1785872: + title: Berry–Esséen theorem + +Q1786292: + title: Schur's theorem + +Q1786419: + title: Kramers' theorem + +Q1789863: + title: Routh's theorem + +Q1809539: + title: Pizza theorem + +Q1816952: + title: Schur's lemma + +Q1841237: + title: Fubini's theorem on differentiation + +Q1855610: + title: Theorem of de Moivre–Laplace + +Q1888583: + title: Holditch's theorem + +Q1893717: + title: Rice's theorem + +Q1896455: + title: Varignon's theorem + +Q1899432: + title: Grothendieck–Hirzebruch–Riemann–Roch theorem + +Q1914905: + title: Ramanujan–Skolem's theorem + +Q1930577: + title: Herbrand's theorem + +Q1933521: + title: Kleene's recursion theorem + +Q1938251: + title: Hasse–Minkowski theorem + +Q1946642X: + title: S–cobordism theorem + +Q1946642: + title: H-cobordism theorem + +Q1964537: + title: Mergelyan's theorem + +Q1966978: + title: Lévy continuity theorem + +Q1974087: + title: Riemann's theorem on removable singularities + +Q1995468: + title: Hölder's theorem + +Q1996305: + title: Burnside's theorem + +Q2000090: + title: Art gallery theorem + +Q2008549: + title: Hilbert's theorem + +Q2013213: + title: Reuschle's theorem + +Q2022775: + title: Hilbert–Schmidt theorem + +Q2027347: + title: Optional stopping theorem + +Q2028341: + title: Ado's theorem + +Q2046647: + title: Karhunen–Loève theorem + +Q2063099: + title: Poincaré duality theorem + +Q2068227: + title: Artin–Schreier theorem + +Q2071632: + title: Rouché–Capelli theorem + +Q2093886: + title: Primitive element theorem + +Q2094241: + title: Hopf–Rinow theorem + +Q2096184: + title: Plancherel theorem + +Q2109761: + title: Uniformization theorem + +Q2120067: + title: Diller–Dress theorem + +Q2190744: + title: Feuerbach's theorem + +Q2197859: + title: Nicomachus's theorem + +Q2222575: + title: Shell theorem + +Q2226602: + title: Bauer–Fike theorem + +Q2226606: + title: Beckman–Quarles theorem + +Q2226610: + title: Banach–Mazur theorem + +Q2226624: + title: Bruck–Chowla–Ryser theorem + +Q2226625: + title: Commandino's theorem + +Q2226640: + title: Cramér’s decomposition theorem + +Q2226644: + title: Easton's theorem + +Q2226650: + title: Eberlein–Šmulian theorem + +Q2226677: + title: Gelfand–Mazur theorem + +Q2226682: + title: Gelfand–Naimark theorem + +Q2226691: + title: Kirchhoff's theorem + +Q2226695: + title: Hurwitz's automorphisms theorem + +Q2226698: + title: Kantorovich theorem + +Q2226709: + title: Krull–Schmidt theorem + +Q2226750: + title: Malgrange–Ehrenpreis theorem + +Q2226774: + title: König's theorem + +Q2226786: + title: Sperner's theorem + +Q2226800: + title: Schur–Zassenhaus theorem + +Q2226803: + title: Tennenbaum's theorem + +Q2226807: + title: Vantieghems theorem + +Q2226855: + title: Sarkovskii's theorem + +Q2226868: + title: Geometric mean theorem + +Q2226962: + title: Weierstrass–Casorati theorem + +Q2253746: + title: Bertrand's ballot theorem + +Q2266397: + title: Intersecting chords theorem + +Q2267175: + title: Tangent-secant theorem + +Q2269888: + title: Cohn's irreducibility criterion + +Q2270905: + title: Poincaré–Birkhoff–Witt theorem + +Q2275191: + title: Lebesgue differentiation theorem + +Q2277040: + title: Shannon's expansion theorem + +Q2287393: + title: Caristi fixed-point theorem + +Q2309682: + title: Sphere theorem + +Q2309760: + title: Looman–Menchoff theorem + +Q2310718: + title: Pitot theorem + +Q2338929: + title: Exchange theorem + +Q2345282: + title: Shannon's theorem + +Q2347139: + title: Carnot's theorem + +Q2360531: + title: Jordan–Schur theorem + +Q2374733: + title: Skolem–Mahler–Lech theorem + +Q2376918: + title: Abelian and Tauberian theorems + +Q2378270: + title: Thue's theorem + +Q2379128: + title: Lindström's theorem + +Q2379132: + title: Going-up and going-down theorems + +Q2394548: + title: Hurewicz theorem + +Q2411312: + title: Shannon's source coding theorem + +Q2428364: + title: Clausius theorem + +Q2449984: + title: Miquel's theorem + +Q2449984X: + title: Pivot theorem + +Q2471737: + title: Carathéodory's theorem + +Q2473965: + title: Ugly duckling theorem + +Q2478371: + title: Envelope theorem + +Q2482753: + title: Mann's theorem + +Q2495664: + title: Universal coefficient theorem + +Q2500406: + title: Liénard's theorem + +Q2500408: + title: Thébault's theorem + +Q2518048: + title: Kodaira vanishing theorem + +Q2524990: + title: Jackson's theorem + +Q2525646: + title: Jordan–Hölder theorem + +Q2533936: + title: Descartes's theorem on total angular defect + +Q2540738: + title: Cartan–Dieudonné theorem + +Q2558669: + title: Artin–Zorn theorem + +Q2588432: + title: Wold's theorem + +Q2600653: + title: Taylor–Proudman theorem + +Q2607007: + title: Hinge theorem + +Q2621667: + title: Nagata–Smirnov metrization theorem + +Q2631152: + title: Carathéodory's extension theorem + +Q2635326: + title: Structured program theorem + +Q2638931: + title: Convolution theorem + +Q2703389: + title: Linnik's theorem + +Q2733672: + title: Price's theorem + +Q2734084: + title: Bohr–Mollerup theorem + +Q2793600: + title: Stark–Heegner theorem + +Q2799491: + title: Ringel–Youngs theorem + +Q2800071: + title: Perfect graph theorem + +Q2862403: + title: Bombieri's theorem + +Q2893695: + title: Unmixedness theorem + +Q2916568: + title: Gomory's theorem + +Q2919401: + title: Ostrowski's theorem + +Q2981012: + title: Monge's theorem + +Q2984415: + title: Hajnal–Szemerédi theorem + +Q2993026: + title: Ankeny–Artin–Chowla theorem + +Q2993308: + title: Cameron–Erdős theorem + +Q2993319: + title: Mirsky–Newman theorem + +Q2995691: + title: Newlander–Niremberg theorem + +Q3001796: + title: Skolem–Noether theorem + +Q3007384: + title: Post's theorem + +Q3075250: + title: Hardy–Littlewood maximal theorem + +Q3077634: + title: Sahlqvist correspondence theorem + +Q3088644: + title: Goldstine theorem + +Q3154003: + title: Le Cam's theorem + +Q3180727: + title: Perlis theorem + +Q3229335: + title: Borel–Carathéodory theorem + +Q3229352: + title: Vitali covering theorem + +Q3345678: + title: Moore–Aronszajn theorem + +Q3424029: + title: Chasles's theorems + +Q3443426: + title: Bondy's theorem + +Q3458641: + title: Szegő limit theorems + +Q3502015: + title: Hasse's theorem on elliptic curves + +Q3505260: + title: Cayley–Salmon theorem + +Q3526969: + title: AF+BG theorem + +Q3526976: + title: Ax–Kochen theorem + +Q3526982: + title: Erdős–Anning theorem + +Q3526990: + title: Euler's theorem + +Q3526993: + title: Takagi existence theorem + +Q3526996: + title: Kolmogorov extension theorem + +Q3526998: + title: Excision theorem + +Q3527004: + title: BEST theorem + +Q3527008: + title: Balian–Low theorem + +Q3527009: + title: Baker's theorem + +Q3527011: + title: Beck's theorem + +Q3527015: + title: Bernstein's theorem + +Q3527017: + title: Beurling–Lax theorem + +Q3527019: + title: Birch's theorem + +Q3527034: + title: Cauchy's theorem + +Q3527040: + title: Chomsky–Schützenberger representation theorem + +Q3527044: + title: Pappus's area theorem + +Q3527054: + title: De Bruijn–Erdős theorem (graph theory) + +Q3527056: + title: De Bruijn–Erdős theorem (incidence geometry) + +Q3527064: + title: Donsker's theorem + +Q3527067: + title: F. and M. Riesz theorem + +Q3527071: + title: Fáry–Milnor theorem + +Q3527079: + title: Freiman's theorem + +Q3527088: + title: Haboush's theorem + +Q3527091: + title: Gromov's theorem on groups of polynomial growth + +Q3527093: + title: Hilbert–Speiser theorem + +Q3527095: + title: Jacobi's four-square theorem + +Q3527100: + title: Kruskal's tree theorem + +Q3527102: + title: Kruskal–Katona theorem + +Q3527110: + title: Lax–Wendroff theorem + +Q3527113: + title: Lie–Kolchin theorem + +Q3527118: + title: Mahler's theorem + +Q3527125: + title: Monsky's theorem + +Q3527129: + title: Müntz–Szász theorem + +Q3527132: + title: Nagell–Lutz theorem + +Q3527155: + title: Robertson–Seymour theorem + +Q3527162: + title: Sophie Germain's theorem + +Q3527166: + title: Steinhaus theorem + +Q3527171: + title: Synge's theorem + +Q3527185: + title: Whitehead theorem + +Q3527189: + title: Lattice theorem + +Q3527196: + title: Principal ideal theorem + +Q3527205: + title: Dimension theorem for vector spaces + +Q3527209: + title: Hasse norm theorem + +Q3527214: + title: Non-squeezing theorem + +Q3527215: + title: Hilbert projection theorem + +Q3527217: + title: M. Riesz extension theorem + +Q3527219: + title: Weierstrass preparation theorem + +Q3527223: + title: Crystallographic restriction theorem + +Q3527226: + title: Linear speedup theorem + +Q3527230: + title: Von Staudt–Clausen theorem + +Q3527233: + title: Kolmogorov's three-series theorem + +Q3527241: + title: Krull's principal ideal theorem + +Q3527245: + title: Six exponentials theorem + +Q3527247: + title: Six circles theorem + +Q3527250: + title: Hadamard three-lines theorem + +Q3527263: + title: Kleene fixed-point theorem + +Q3527279: + title: Wiener's tauberian theorem + +Q3534036: + title: Pompeiu's theorem + +Q3613173: + title: Tits alternative + +Q3661294: + title: Kelvin's circulation theorem + +Q3699212: + title: Saint-Venant's theorem + +Q3711848: + title: Sobolev embedding theorem + +Q3757563: + title: Intercept theorem + +Q3771212: + title: Proth's theorem + +Q3889376: + title: Carmichael's theorem + +Q3893473: + title: Tameness theorem + +Q3915398: + title: Brunn–Minkowski theorem + +Q3983968: + title: Sturm–Picone comparison theorem + +Q3983972: + title: Simplicial approximation theorem + +Q3984011: + title: Duggan–Schwartz theorem + +Q3984017: + title: Helly's selection theorem + +Q3984020: + title: Holmström's theorem + +Q3984052: + title: Equidistribution theorem + +Q3984053: + title: Fourier inversion theorem + +Q3984056: + title: No-communication theorem + +Q3984063: + title: Mostow rigidity theorem + +Q3984069: + title: Fredholm's theorem + +Q4054114: + title: ATS theorem + +Q4116459: + title: Niven's theorem + +Q4171386: + title: Soul theorem + +Q4179283: + title: Positive energy theorem + +Q4272300: + title: Initial value theorem + +Q4272645: + title: Final value theorem + +Q4378868: + title: Phragmén–Lindelöf theorem + +Q4378889: + title: Carathéodory's theorem + +Q4408070: + title: De Finetti's theorem + +Q4454910: + title: Ostrowski–Hadamard gap theorem + +Q4454919: + title: Aumann's agreement theorem + +Q4454925: + title: Edge-of-the-wedge theorem + +Q4454954: + title: Kirszbraun theorem + +Q4454958: + title: Min-max theorem + +Q4454973: + title: Lindelöf's theorem + +Q4454976: + title: Liouville's theorem + +Q4454989: + title: Meusnier's theorem + +Q4454996: + title: Novikov's compact leaf theorem + +Q4455003: + title: Pomeranchuk's theorem + +Q4455015: + title: Routh–Hurwitz theorem + +Q4455016: + title: Reeb sphere theorem + +Q4455023: + title: Sazonov's theorem + +Q4455025: + title: No wandering domain theorem + +Q4455030: + title: Stone's theorem on one-parameter unitary groups + +Q4455031: + title: Fáry's theorem + +Q4455033: + title: Fatou's theorem + +Q4455037: + title: Hardy's theorem + +Q4455043: + title: Cayley–Bacharach theorem + +Q4455046: + title: Monodromy theorem + +Q4634017: + title: 2π theorem + +Q4663326: + title: Hirzebruch–Riemann–Roch theorem + +Q4666729: + title: Abel–Jacobi theorem + +Q4666729X: + title: Abel's curve theorem + +Q4667501: + title: Abhyankar–Moh theorem + +Q4677985: + title: Acyclic models theorem + +Q4695203: + title: Four functions theorem + +Q4700718: + title: Akhiezer's theorem + +Q4712316: + title: Albert–Brauer–Hasse–Noether theorem + +Q4713046: + title: Alchian–Allen theorem + +Q4724004B: + title: Riemann's existence theorem + +Q4724004A: + title: Chow's theorem + +Q4734002: + title: Gromov–Ruh theorem + +Q4734844: + title: Alperin–Brauer–Gorenstein theorem + +Q4736422: + title: Denjoy theorem + +Q4746948: + title: Amitsur–Levitzki theorem + +Q4751110: + title: Analyst's traveling salesman theorem + +Q4751118: + title: Analytic Fredholm theorem + +Q4753992: + title: Anderson's theorem + +Q4756099: + title: Andreotti–Frankel theorem + +Q4783822: + title: Arithmetic Riemann–Roch theorem + +Q4788680: + title: Area theorem (conformal mapping) + +Q4801169: + title: Artin approximation theorem + +Q4801183: + title: Artin–Verdier duality theorem + +Q4801563: + title: Artstein's theorem + +Q4815879: + title: Atiyah–Segal completion theorem + +Q4815899: + title: Atkinson's theorem + +Q4826848: + title: Autonomous convergence theorem + +Q4827308: + title: Auxiliary polynomial theorem + +Q4830725: + title: Ax–Grothendieck theorem + +Q4832965: + title: Aztec diamond theorem + +Q4838119: + title: Babuška–Lax–Milgram theorem + +Q4848497: + title: Baily–Borel theorem + +Q4853767: + title: Banach–Stone theorem + +Q4857506: + title: Bapat–Beg theorem + +Q4865980: + title: Barwise compactness theorem + +Q4866385: + title: Base change theorems + +Q4866385X: + title: Proper base change theorem + +Q4877965: + title: Beauville–Laszlo theorem + +Q4878586: + title: Beck's monadicity theorem + +Q4880958: + title: Behnke–Stein theorem + +Q4884789: + title: Beltrami's theorem + +Q4884950: + title: Belyi's theorem + +Q4891633: + title: Berger–Kazdan comparison theorem + +Q4894565: + title: Bernstein's theorem + +Q4914101: + title: Bing's recognition theorem + +Q4916483: + title: Birkhoff–Grothendieck theorem + +Q4918128: + title: Bishop–Cannings theorem + +Q4927458: + title: Blondel's theorem + +Q4937691: + title: Bogoliubov–Parasyuk theorem + +Q4941364: + title: Bondareva–Shapley theorem + +Q4942215: + title: Bonnet theorem + +Q4944906: + title: Borel determinacy theorem + +Q4944908: + title: Borel fixed-point theorem + +Q4944923: + title: Borel–Bott–Weil theorem + +Q4944923X: + title: Borel–Weil theorem + +Q4948983: + title: Bott periodicity theorem + +Q4949984: + title: Bounded inverse theorem + +Q4950096: + title: Bourbaki–Witt theorem + +Q4956438: + title: Branching theorem + +Q4958218: + title: Brauer's theorem on induced characters + +Q4958221: + title: Brauer's three main theorems + +Q4958227: + title: Brauer–Nesbitt theorem + +Q4958230: + title: Brauer–Siegel theorem + +Q4958233: + title: Brauer–Suzuki–Wall theorem + +Q4971339: + title: British flag theorem + +Q4975963: + title: Brown's representability theorem + +Q4979609: + title: Brun–Titchmarsh theorem + +Q4991415: + title: Chowla–Mordell theorem + +Q4998912: + title: Burke's theorem + +Q5001327: + title: Busemann's theorem + +Q5005143: + title: Bôcher's theorem + +Q5005965: + title: C-theorem + +Q5026435: + title: Cameron–Martin theorem + +Q5037752: + title: Carathéodory's existence theorem + +Q5041175: + title: Carleson–Jacobs theorem + +Q5042898: + title: Carlson's theorem + +Q5047043: + title: Cartan's theorems A and B + +Q5047046: + title: Brauer–Cartan–Hua theorem + +Q5047048: + title: Cartan–Hadamard theorem + +Q5047051: + title: Cartan–Kuranishi prolongation theorem + +Q5047052: + title: Cartan–Kähler theorem + +Q5049717: + title: Castelnuovo–de Franchis theorem + +Q5091194: + title: Cheng's eigenvalue comparison theorem + +Q5094298: + title: Chevalley's structure theorem + +Q5094305: + title: Chevalley–Shephard–Todd theorem + +Q5103861: + title: Choi's theorem on completely positive maps + +Q5125859: + title: Clapeyron's theorem + +Q5127710: + title: Clark–Ocone theorem + +Q5132839: + title: Clifford's circle theorems + +Q5132840: + title: Clifford's theorem on special divisors + +Q5136698: + title: Cluster decomposition theorem + +Q5139948: + title: Codd's theorem + +Q5141331: + title: Cohen structure theorem + +Q5155090: + title: Commutation theorem + +Q5157054: + title: Compression theorem + +Q5161245: + title: Conley–Zehnder theorem + +Q5163116: + title: Conservativity theorem + +Q5165492: + title: Continuous mapping theorem + +Q5166389: + title: Van Vleck's theorem + +Q5171652: + title: Corners theorem + +Q5172143: + title: Corona theorem + +Q5178114: + title: Courcelle's theorem + +Q5180651: + title: Craig's theorem + +Q5187911: + title: Crooks fluctuation theorem + +Q5188510: + title: Crossbar theorem + +Q5195996: + title: Curtis–Hedlund–Lyndon theorem + +Q5221089: + title: Danskin's theorem + +Q5242704: + title: Dawson–Gärtner theorem + +Q5244285: + title: de Bruijn's theorem + +Q5244361: + title: De Franchis theorem + +Q5251122: + title: Time hierarchy theorem + +Q5252320: + title: Lickorish twist theorem + +Q5278348: + title: Galvin's theorem + +Q5282059: + title: Harish–Chandra theorem + +Q5282247: + title: Disintegration theorem + +Q5295351: + title: Donaldson's theorem + +Q5296972: + title: Doob–Meyer decomposition theorem + +Q5299605: + title: Glivenko's theorem + +Q5311783: + title: Dudley's theorem + +Q5315060: + title: Dunford–Schwartz theorem + +Q5319505: + title: Zeilberger–Bressoud theorem + +Q5337931: + title: Edgeworth's limit theorem + +Q5362000: + title: Elitzur's theorem + +Q5384150: + title: Equal incircles theorem + +Q5385323: + title: Erdős–Gallai theorem + +Q5385324: + title: Erdős–Nagy theorem + +Q5385325: + title: Erdős–Pósa theorem + +Q5385326: + title: Erdős–Stone theorem + +Q5421989: + title: Exterior angle theorem + +Q5436274: + title: Farrell–Markushevich theorem + +Q5437947: + title: Fatou–Lebesgue theorem + +Q5438320: + title: Faustman–Ohlin theorem + +Q5443003: + title: Fenchel's duality theorem + +Q5443004: + title: Fenchel's theorem + +Q5443005: + title: Fenchel–Moreau theorem + +Q5445112: + title: Fernique's theorem + +Q5445311: + title: Ferrero–Washington theorem + +Q5447238: + title: Fieller's theorem + +Q5454965: + title: Fisher–Tippett–Gnedenko theorem + +Q5455495: + title: Fitting's theorem + +Q5456213: + title: Five circles theorem + +Q5463860: + title: Focal subgroup theorem + +Q5473576: + title: Foster's theorem + +Q5494134: + title: Fraňková–Helly selection theorem + +Q5498822: + title: Birkhoff's theorem + +Q5499906: + title: Shirshov–Witt theorem + +Q5501344: + title: Freidlin–Wentzell theorem + +Q5503689: + title: Bombieri–Friedlander–Iwaniec theorem + +Q5504427: + title: Friendship theorem + +Q5505098: + title: Frobenius determinant theorem + +Q5505114: + title: Froda's theorem + +Q5506929: + title: Fuchs's theorem + +Q5507285: + title: Fuglede's theorem + +Q5508180: + title: Full employment theorem + +Q5508482: + title: Fulton–Hansen connectedness theorem + +Q5508973: + title: Fundamental theorem of arbitrage-free pricing + +Q5530454: + title: Gell-Mann and Low theorem + +Q5552370: + title: Geroch's splitting theorem + +Q5566491: + title: Glaisher's theorem + +Q5567394: + title: Gleason's theorem + +Q5576268: + title: Goddard–Thorn theorem + +Q5579030: + title: Goldberg–Sachs theorem + +Q5580171: + title: Goldie's theorem + +Q5586067: + title: Gordon–Newell theorem + +Q5588002: + title: Gottesman–Knill theorem + +Q5597098: + title: Graph structure theorem + +Q5609384: + title: Grinberg's theorem + +Q5610188: + title: Gromov's compactness theorem + +Q5610190: + title: Gromov's compactness theorem + +Q5610718: + title: Grothendieck's connectedness theorem + +Q5612131: + title: Grunsky's theorem + +Q5612159: + title: Grunwald–Wang theorem + +Q5612871: + title: Grötzsch's theorem + +Q5638112: + title: Hadwiger's theorem + +Q5638886: + title: Hahn embedding theorem + +Q5643485: + title: Halpern–Läuchli theorem + +Q5645731: + title: Hammersley–Clifford theorem + +Q5656673: + title: Hardy–Littlewood tauberian theorem + +Q5656674: + title: Hardy–Ramanujan theorem + +Q5657833: + title: Harish–Chandra's regularity theorem + +Q5659675: + title: Harnack's curve theorem + +Q5675112: + title: Hartogs–Rosenthal theorem + +Q5680041: + title: Hasse–Arf theorem + +Q5697916B: + title: Waldhausen's theorem + +Q5697916A: + title: Reidemeister–Singer Theorem + +Q5697927: + title: Gross–Zagier theorem + +Q5709171: + title: Helly–Bray theorem + +Q5709377: + title: Helmholtz theorem (classical mechanics) + +Q5761142: + title: Hilbert's irreducibility theorem + +Q5874979: + title: Hobby–Rice theorem + +Q5876058: + title: Hodge index theorem + +Q5988409: + title: Identity theorem for Riemann surfaces + +Q6015420: + title: Increment theorem + +Q6059532: + title: Aronszajn–Smith theorem + +Q6086104: + title: Isomorphism extension theorem + +Q6119825: + title: Jacobson–Bourbaki theorem + +Q6276298: + title: Jordan's theorem (multiply transitive groups) + +Q6344729: + title: Kachurovskii's theorem + +Q6360586: + title: Kanamori–McAloon theorem + +Q6373327: + title: Karp–Lipton theorem + +Q6378596: + title: Katz–Lang finiteness theorem + +Q6379606: + title: Kawamata–Viehweg vanishing theorem + +Q6379715: + title: Kawasaki's theorem + +Q6387087: + title: Kempf–Ness theorem + +Q6400676: + title: Kharitonov's theorem + +Q6402928: + title: Lagrange reversion theorem + +Q6403282: + title: Lagrange's theorem + +Q6407842: + title: Killing–Hopf theorem + +Q6414200: + title: Kinoshita–Lee–Nauenberg theorem + +Q6421981: + title: Kneser's theorem + +Q6425088: + title: Kodaira embedding theorem + +Q6436753: + title: Krener's theorem + +Q6442276: + title: Kuiper's theorem + +Q6446396: + title: Kurosh subgroup theorem + +Q6455211: + title: Kōmura's theorem + +Q6456122: + title: L-balance theorem + +Q6471668: + title: Lafforgue's theorem + +Q6481192: + title: Lambek–Moser theorem + +Q6484331: + title: Landau prime ideal theorem + +Q6501470: + title: Lauricella's theorem + +Q6513990: + title: Lee Hwa Chung theorem + +Q6516611: + title: Lee–Yang theorem + +Q6516731: + title: Lefschetz hyperplane theorem + +Q6516736: + title: Lefschetz theorem on (1,1)-classes + +Q6528747: + title: Leray's theorem + +Q6528751: + title: Leray–Hirsch theorem + +Q6528849: + title: Lerner symmetry theorem + +Q6535568: + title: Levi's theorem + +Q6535741: + title: Levitzky's theorem + +Q6544508: + title: Lie–Palais theorem + +Q6701653: + title: Lukacs's proportion-sum independence theorem + +Q6707093: + title: Lyapunov–Malkin theorem + +Q6711207: + title: Lévy's modulus of continuity theorem + +Q6722024: + title: MacMahon Master theorem + +Q6733278: + title: Maharam's theorem + +Q6734194: + title: Mahler's compactness theorem + +Q6735549: + title: Maier's theorem + +Q6743217: + title: Malgrange preparation theorem + +Q6749789: + title: Manin–Drinfeld theorem + +Q6757284: + title: Marcinkiewicz theorem + +Q6760432: + title: Marginal value theorem + +Q6771536: + title: Markus−Yamabe theorem + +Q6777133: + title: Martingale representation theorem + +Q6783821: + title: Mason–Stothers theorem + +Q6795637: + title: Maximal ergodic theorem + +Q6795830: + title: Separating axis theorem + +Q6796056: + title: Maxwell's theorem + +Q6799039: + title: Mazur's control theorem + +Q6813106: + title: Mellin inversion theorem + +Q6859627: + title: Milliken's tree theorem + +Q6859648: + title: Milliken–Taylor theorem + +Q6860180: + title: Milman–Pettis theorem + +Q6867853: + title: Minkowski's second theorem + +Q6867867: + title: Minkowski–Hlawka theorem + +Q6867878: + title: Minlos's theorem + +Q6911202: + title: Moreau's theorem + +Q6914794: + title: Morton's theorem + +Q6925496: + title: Mountain pass theorem + +Q6927135: + title: Moving equilibrium theorem + +Q6935007: + title: Multiplicity-one theorem + +Q6935403: + title: Mumford vanishing theorem + +Q6957141: + title: Nachbin's theorem + +Q6967039: + title: Nash–Moser theorem + +Q7020025: + title: Newton's theorem about ovals + +Q7031618: + title: Nielsen realization problem + +Q7031621: + title: Nielsen fixed-point theorem + +Q7042768: + title: No-broadcasting theorem + +Q7042801: + title: No-trade theorem + +Q7043732: + title: Kuhn's theorem + +Q7045226: + title: No free lunch theorem + +Q7047379: + title: Noether's theorem on rationality for surfaces + +Q7098850: + title: Optical equivalence theorem + +Q7100033A: + title: Orbit theorem (Nagano–Sussmann) + +Q7100033B: + title: Rashevsky–Chow theorem + +Q7103669: + title: Ornstein theorem + +Q7106480: + title: Oseledec theorem + +Q7127466: + title: Paley's theorem + +Q7130794: + title: Pandya theorem + +Q7137494: + title: Paris–Harrington theorem + +Q7139570: + title: Parovicenko's theorem + +Q7140218: + title: Parthasarathy's theorem + +Q7160302: + title: Peeling theorem + +Q7160489: + title: Peetre theorem + +Q7160983: + title: Peixoto's theorem + +Q7190748: + title: Pickands–Balkema–de Haan theorem + +Q7200963: + title: Planar separator theorem + +Q7208500: + title: Poisson limit theorem + +Q7239984: + title: Preimage theorem + +Q7245073: + title: Principal axis theorem + +Q7249519: + title: Prokhorov's theorem + +Q7255475: + title: Pseudorandom generator theorem + +Q7269076: + title: No-deleting theorem + +Q7269106: + title: Quantum threshold theorem + +Q7269437: + title: Denjoy–Carleman theorem + +Q7269559: + title: Sylvester pentahedral theorem + +Q7272004: + title: Quillen–Suslin theorem + +Q7272898: + title: Quotient of subspace theorem + +Q7283856: + title: Raikov's theorem + +Q7288988: + title: Ramanujam vanishing theorem + +Q7295875: + title: Ratner's theorems + +Q7296106: + title: Rauch comparison theorem + +Q7307252: + title: Reflection theorem + +Q7308146: + title: Regev's theorem + +Q7309601: + title: Whitney–Graustein Theorem + +Q7310041: + title: Reider's theorem + +Q7312009: + title: Remmert–Stein theorem + +Q7318284: + title: Reversed compound agent theorem + +Q7322366: + title: Ribet's theorem + +Q7323144: + title: Rice–Shapiro theorem + +Q7333126: + title: Riemann–Roch theorem for surfaces + +Q7341043: + title: Robbins theorem + +Q7352955: + title: Robinson's joint consistency theorem + +Q7359997: + title: Rokhlin's theorem + +Q7396621: + title: Saccheri–Legendre theorem + +Q7430892: + title: Schaefer's dichotomy theorem + +Q7431298: + title: Schilder's theorem + +Q7431925: + title: Schnyder's theorem + +Q7432872: + title: Schreier refinement theorem + +Q7432915: + title: Schroeder–Bernstein theorem for measurable spaces + +Q7432918: + title: Schröder–Bernstein theorems for operator algebras + +Q7433034: + title: Great orthogonality theorem + +Q7433182: + title: Schwartz–Zippel theorem + +Q7433295: + title: Osterwalder–Schrader theorem + +Q7437564: + title: Scott core theorem + +Q7455422: + title: Swan's theorem + +Q7496252: + title: Shift theorem + +Q7510574: + title: Siegel–Walfisz theorem + +Q7512855: + title: Hirzebruch signature theorem + +Q7516736: + title: Silverman–Toeplitz theorem + +Q7524563: + title: Sinkhorn's theorem + +Q7525341: + title: Sion's minimax theorem + +Q7525845: + title: Sipser–Lautemann theorem + +Q7532192: + title: Siu's semicontinuity theorem + +Q7536097: + title: Skoda–El Mir theorem + +Q7536350: + title: Skorokhod's embedding theorem + +Q7572588: + title: Space hierarchy theorem + +Q7574438: + title: Specht's theorem + +Q7597316: + title: Stallings theorem about ends of groups + +Q7597317: + title: Stallings–Zeeman theorem + +Q7599389: + title: Stanley's reciprocity theorem + +Q7601243: + title: Star of David theorem + +Q7606897: + title: Steinitz theorem + +Q7606940: + title: Stein–Strömberg theorem + +Q7617407: + title: Stinespring factorization theorem + +Q7619060: + title: The duality theorem + +Q7619449: + title: Stone–von Neumann theorem + +Q7621715: + title: Strassmann's theorem + +Q7625164: + title: Structure theorem for Gaussian measures + +Q7632041: + title: Subspace theorem + +Q7644264: + title: Supersymmetry nonrenormalization theorems + +Q7660749: + title: Sylvester's determinant theorem + +Q7661308: + title: Symmetric hypergraph theorem + +Q7664013: + title: Sz.-Nagy's dilation theorem + +Q7686760: + title: Bang's theorem + +Q7782345: + title: Bertini's theorem + +Q7782346: + title: Theorem of the cube + +Q7782348: + title: Theorem of three moments + +Q7795825: + title: Thompson transitivity theorem + +Q7795828: + title: Thompson uniqueness theorem + +Q7809920: + title: Titchmarsh convolution theorem + +Q7818977: + title: Tomita's theorem + +Q7820874: + title: Tonelli's theorem + +Q7824894: + title: Topkis's theorem + +Q7825061: + title: Toponogov's theorem + +Q7825663: + title: Torelli theorem + +Q7827204: + title: Mazur's torsion theorem + +Q7841060: + title: Trichotomy theorem + +Q7845353: + title: Trombi–Varadarajan theorem + +Q7847268: + title: Trudinger's theorem + +Q7849521: + title: Tsen's theorem + +Q7853325: + title: Tunnell's theorem + +Q7856599: + title: Turán–Kubilius theorem + +Q7857350: + title: Tverberg's theorem + +Q7888360: + title: Structure theorem for finitely generated modules over a principal ideal domain + +Q7894110: + title: Universal approximation theorem + +Q7911648: + title: Valiant–Vazirani theorem + +Q7928688: + title: Vietoris–Begle mapping theorem + +Q7936914: + title: Vitali–Hahn–Saks theorem + +Q7941491: + title: Von Neumann's theorem + +Q7959587: + title: Wagner's theorem + +Q7966545: + title: Walter theorem + +Q7978735: + title: Weber's theorem + +Q7980241: + title: Weinberg–Witten theorem + +Q7996766: + title: Whitney extension theorem + +Q7996769: + title: Whitney immersion theorem + +Q7999144: + title: Wiener–Ikehara theorem + +Q7999797: + title: Beer's theorem + +Q8002487: + title: Wilkie's theorem + +Q8028529: + title: Witt's theorem + +Q8062800: + title: Z* theorem + +Q8063120: + title: ZJ theorem + +Q8064722: + title: Zahorski theorem + +Q8066611: + title: Kövari–Sós–Turán theorem + +Q8066795: + title: Zariski's main theorem + +Q8074796: + title: Zsigmondy's theorem + +Q8081891: + title: Śleszyński–Pringsheim theorem + +Q9993851: + title: Lax–Milgram theorem + +Q10369454: + title: Noether's second theorem + +Q10859514: + title: Vafa–Witten theorem + +Q10942247: + title: Hironaka theorem + +Q11352023: + title: Vitali convergence theorem + +Q11573495: + title: Plancherel theorem for spherical functions + +Q11704319: + title: Chern–Gauss–Bonnet theorem + +Q11722674: + title: Takens's theorem + +Q11883897: + title: Nagata's compactification theorem + +Q15080987: + title: Lie's third theorem + +Q15813392: + title: Barban–Davenport–Halberstam theorem + +Q15830473: + title: Morley's categoricity theorem + +Q15844093: + title: Van Schooten's theorem + +Q15859323: + title: Anne's theorem + +Q15872491: + title: Newton's theorem (quadrilateral) + +Q15895894: + title: Finsler–Hadwiger theorem + +Q16251580: + title: Matiyasevich's theorem + +Q16680059: + title: Strong perfect graph theorem + +Q16978447: + title: Grauert–Riemenschneider vanishing theorem + +Q17001601: + title: 2-factor theorem + +Q17002391: + title: Arrow-Lind theorem + +Q17003552: + title: Alexandrov's uniqueness theorem + +Q17005116: + title: Birkhoff's representation theorem + +Q17008559: + title: Davenport–Schmidt theorem + +Q17017973: + title: Godunov's theorem + +Q17018210: + title: Golod–Shafarevich theorem + +Q17019684: + title: Grushko theorem + +Q17029787: + title: Higman's embedding theorem + +Q17080564: + title: Zariski's connectedness theorem + +Q17081508: + title: Bing metrization theorem + +Q17082552: + title: Mutual fund separation theorem + +Q17089994X: + title: Tikhonov fixed-point theorem + +Q17089994: + title: Fixed-point theorems in infinite-dimensional spaces + +Q17098075: + title: Jurkat–Richert theorem + +Q17098298: + title: Jacobson density theorem + +Q17098379: + title: Kaplansky's theorem on quadratic forms + +Q17101806: + title: Intersection theorem + +Q17102744: + title: Riemann–Roch theorem for smooth manifolds + +Q17103352: + title: Maximum power theorem + +Q17104025: + title: Riemann singularity theorem + +Q17104863: + title: Nielsen–Ninomiya theorem + +Q17125544: + title: Lickorish–Wallace theorem + +Q18205730: + title: Byers–Yang theorem + +Q18206032: + title: Cartan's theorem + +Q18206266: + title: Euclid–Euler theorem + +Q18630480: + title: Euler's quadrilateral theorem + +Q19323571: + title: Chomsky–Schützenberger enumeration theorem + +Q19779530: + title: Thomsen's theorem + +Q20278711: + title: Cramer's theorem (algebraic curves) + +Q20971632: + title: Lie's theorem + +Q22952648: + title: Uncountability of the continuum + +Q25099402: + title: Kolmogorov–Arnold representation theorem + +Q25303622: + title: Browder–Minty theorem + +Q25304227: + title: Arakelyan's theorem + +Q25304301: + title: Bregman–Minc inequality + +Q25345219: + title: BBD decomposition theorem + +Q25378690: + title: Ionescu-Tulcea theorem + +Q26877569: + title: Furry's theorem + +Q28194853: + title: Lovelock's theorem + +Q28458131: + title: Glivenko's theorem + +Q31838822: + title: Kirchberger's theorem + +Q48996535: + title: Solèr's theorem + +Q48998319: + title: Frobenius reciprocity theorem + +Q55647729: + title: Cramér's theorem (large deviations) + +Q56291669: + title: Alspach's theorem + +Q60681777: + title: Constant chord theorem + +Q61163749: + title: Theorem of the gnomon + +Q62051012: + title: Behrend's theorem + +Q96375449: + title: Conway circle theorem + +Q96377355: + title: Erdős–Dushnik–Miller theorem + +Q97359729: + title: Stahl's theorem + +Q104841721: + title: Jacobson–Morozov theorem + +Q104871594: + title: Joubert's theorem + +Q105222412: + title: Five color theorem + +Q107535899: + title: Bochner's tube theorem + +Q107547910: + title: Malgrange–Zerner theorem + +Q107709489: + title: Büchi-Elgot-Trakhtenbrot theorem + +Q107710112: + title: Cantor's isomorphism theorem + +Q110921617: + title: Feferman–Vaught theorem + +Q111982312: + title: Friedberg–Muchnik theorem + +Q112659261: + title: Gamas's Theorem + +Q112740521: + title: Netto's theorem diff --git a/docs/references.bib b/docs/references.bib index 976afa9ae6d69..69f11f4a17b95 100644 --- a/docs/references.bib +++ b/docs/references.bib @@ -2602,6 +2602,16 @@ @Article{ markowsky1976 pages = {53-68} } +@Article{ mason2017, + title = {Vertex rings and Pierce bundles}, + author = {Geoffrey Mason}, + year = {2017}, + eprint = {1707.00328}, + archiveprefix = {arXiv}, + primaryclass = {math.RA}, + url = {https://arxiv.org/abs/1707.00328v1} +} + @InProceedings{ mathlib2020, author = {The mathlib Community}, title = {The Lean Mathematical Library}, @@ -2620,6 +2630,17 @@ @InProceedings{ mathlib2020 series = {CPP 2020} } +@Article{ matsuo1997, + title = {On axioms for a vertex algebra and locality of quantum + fields}, + author = {Atsushi Matsuo, Kiyokazu Nagatomo}, + year = {1997}, + eprint = {9706118}, + archiveprefix = {arXiv}, + primaryclass = {hep-th}, + url = {https://arxiv.org/abs/hep-th/9706118} +} + @Book{ mattila1995, author = {Mattila, Pertti}, title = {Geometry of sets and measures in {E}uclidean spaces}, diff --git a/lake-manifest.json b/lake-manifest.json index 57203830de6b6..df098d92919ba 100644 --- a/lake-manifest.json +++ b/lake-manifest.json @@ -1,85 +1,85 @@ {"version": "1.1.0", "packagesDir": ".lake/packages", "packages": - [{"url": "https://github.com/leanprover-community/batteries", + [{"url": "https://github.com/leanprover-community/plausible", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "c933dd9b00271d869e22b802a015092d1e8e454a", - "name": "batteries", + "rev": "8e5cb8d424df462f84997dd68af6f40e347c3e35", + "name": "plausible", "manifestFile": "lake-manifest.json", - "inputRev": "main", + "inputRev": "v4.15.0-rc1", "inherited": false, "configFile": "lakefile.toml"}, - {"url": "https://github.com/leanprover-community/quote4", + {"url": "https://github.com/leanprover-community/LeanSearchClient", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "303b23fbcea94ac4f96e590c1cad6618fd4f5f41", - "name": "Qq", + "rev": "d7caecce0d0f003fd5e9cce9a61f1dd6ba83142b", + "name": "LeanSearchClient", "manifestFile": "lake-manifest.json", - "inputRev": "master", + "inputRev": "main", "inherited": false, - "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover-community/aesop", + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/import-graph", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "de91b59101763419997026c35a41432ac8691f15", - "name": "aesop", + "rev": "ed3b856bd8893ade75cafe13e8544d4c2660f377", + "name": "importGraph", "manifestFile": "lake-manifest.json", - "inputRev": "master", + "inputRev": "v4.15.0-rc1", "inherited": false, "configFile": "lakefile.toml"}, {"url": "https://github.com/leanprover-community/ProofWidgets4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "1383e72b40dd62a566896a6e348ffe868801b172", + "rev": "2b000e02d50394af68cfb4770a291113d94801b5", "name": "proofwidgets", "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.46", + "inputRev": "v0.0.48", "inherited": false, "configFile": "lakefile.lean"}, - {"url": "https://github.com/leanprover/lean4-cli", + {"url": "https://github.com/leanprover-community/aesop", "type": "git", "subDir": null, - "scope": "leanprover", - "rev": "726b3c9ad13acca724d4651f14afc4804a7b0e4d", - "name": "Cli", + "scope": "leanprover-community", + "rev": "43bcb1964528411e47bfa4edd0c87d1face1fce4", + "name": "aesop", "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, + "inputRev": "master", + "inherited": false, "configFile": "lakefile.toml"}, - {"url": "https://github.com/leanprover-community/import-graph", + {"url": "https://github.com/leanprover-community/quote4", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "119b022b3ea88ec810a677888528e50f8144a26e", - "name": "importGraph", + "rev": "ad942fdf0b15c38bface6acbb01d63855a2519ac", + "name": "Qq", "manifestFile": "lake-manifest.json", - "inputRev": "main", + "inputRev": "v4.14.0", "inherited": false, - "configFile": "lakefile.toml"}, - {"url": "https://github.com/leanprover-community/LeanSearchClient", + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/batteries", "type": "git", "subDir": null, "scope": "leanprover-community", - "rev": "d7caecce0d0f003fd5e9cce9a61f1dd6ba83142b", - "name": "LeanSearchClient", + "rev": "74dffd1a83cdd2969a31c9892b0517e7c6f50668", + "name": "batteries", "manifestFile": "lake-manifest.json", "inputRev": "main", "inherited": false, "configFile": "lakefile.toml"}, - {"url": "https://github.com/leanprover-community/plausible", + {"url": "https://github.com/leanprover/lean4-cli", "type": "git", "subDir": null, - "scope": "leanprover-community", - "rev": "42dc02bdbc5d0c2f395718462a76c3d87318f7fa", - "name": "plausible", + "scope": "leanprover", + "rev": "0c8ea32a15a4f74143e4e1e107ba2c412adb90fd", + "name": "Cli", "manifestFile": "lake-manifest.json", "inputRev": "main", - "inherited": false, + "inherited": true, "configFile": "lakefile.toml"}], "name": "mathlib", "lakeDir": ".lake"} diff --git a/lakefile.lean b/lakefile.lean index cab011aba5693..7f2926ad0e7c5 100644 --- a/lakefile.lean +++ b/lakefile.lean @@ -8,13 +8,12 @@ open Lake DSL -/ require "leanprover-community" / "batteries" @ git "main" -require "leanprover-community" / "Qq" @ git "master" +require "leanprover-community" / "Qq" @ git "v4.14.0" require "leanprover-community" / "aesop" @ git "master" -require "leanprover-community" / "proofwidgets" @ git "v0.0.46" -require "leanprover-community" / "importGraph" @ git "main" +require "leanprover-community" / "proofwidgets" @ git "v0.0.48" +require "leanprover-community" / "importGraph" @ git "v4.15.0-rc1" require "leanprover-community" / "LeanSearchClient" @ git "main" - from git "https://github.com/leanprover-community/LeanSearchClient" @ "main" -require "leanprover-community" / "plausible" @ git "main" +require "leanprover-community" / "plausible" @ git "v4.15.0-rc1" /-! ## Options for building mathlib diff --git a/lean-toolchain b/lean-toolchain index 57a4710c03ea5..cf25a9816f061 100644 --- a/lean-toolchain +++ b/lean-toolchain @@ -1 +1 @@ -leanprover/lean4:v4.14.0-rc2 +leanprover/lean4:v4.15.0-rc1 diff --git a/scripts/README.md b/scripts/README.md index 3962da0193667..8cc2baee843ad 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -67,6 +67,10 @@ to learn about it as well! - finally, merge the new branch back into `nightly-testing`, if conflict resolution was required. If there are merge conflicts, it pauses and asks for help from the human driver. +- `merge-lean-testing-pr.sh` takes a PR number `NNNN` as argument, + and attempts to merge the branch `lean-pr-testing-NNNN` into `master`. + It will resolve conflicts in `lean-toolchain`, `lakefile.lean`, and `lake-manifest.json`. + If there are more conflicts, it will bail. **Managing and tracking technical debt** - `technical-debt-metrics.sh` diff --git a/scripts/bench/temci-config.run.yml b/scripts/bench/temci-config.run.yml index 679eb6a0e6d8f..0d3692b08a9fb 100644 --- a/scripts/bench/temci-config.run.yml +++ b/scripts/bench/temci-config.run.yml @@ -7,7 +7,7 @@ rusage_properties: ['maxrss'] cmd: | # use build cache for proofwidgets, but not for anything else - bash -c 'set -eo pipefail; lake clean 1>&2 && LEAN_PATH=$(lean --print-libdir) lake build proofwidgets 1>&2 && rm -f .lake/packages/batteries/.lake/build/bin/runLinter 1>&2 && lake build --no-cache -v --lean ./scripts/bench/fake-root/bin/lean | ./scripts/bench/accumulate_profile.py | grep -v took' + bash -c 'set -eo pipefail; lake clean 1>&2 && LEAN_PATH=$(lean --print-libdir) lake build proofwidgets 1>&2 && rm -f .lake/packages/batteries/.lake/build/bin/runLinter 1>&2 && LAKE_OVERRIDE_LEAN=true LEAN=$(readlink -m ./scripts/bench/fake-root/bin/lean) lake build --no-cache -v | ./scripts/bench/accumulate_profile.py | grep -v took' parse_output: true runs: 1 - attributes: diff --git a/scripts/bench_summary.lean b/scripts/bench_summary.lean index 17f0467b2ef97..9491ddef2ee99 100644 --- a/scripts/bench_summary.lean +++ b/scripts/bench_summary.lean @@ -192,9 +192,9 @@ def addBenchSummaryComment (PR : Nat) (repo : String) (jobID : String := "") -- retrieve the data from the speed-center let curlSpeedCenter : IO.Process.SpawnArgs := { cmd := "curl" - args := #[s!"http://speed.lean-fro.org/mathlib4/api/compare/{source}/to/{target}?all_values=true"] } + args := #[s!"https://speed.lean-lang.org/mathlib4/api/compare/{source}/to/{target}?all_values=true"] } dbg_trace "\n#running\n\ - curl http://speed.lean-fro.org/mathlib4/api/compare/{source}/to/{target}?all_values=true > {tempFile}.src" + curl https://speed.lean-lang.org/mathlib4/api/compare/{source}/to/{target}?all_values=true > {tempFile}.src" let bench ← IO.Process.run curlSpeedCenter IO.FS.writeFile (tempFile ++ ".src") bench diff --git a/scripts/check-yaml.lean b/scripts/check-yaml.lean index 89147aeed4c13..37da03fd90436 100644 --- a/scripts/check-yaml.lean +++ b/scripts/check-yaml.lean @@ -7,11 +7,11 @@ import Lean.Util.SearchPath import Mathlib.Lean.CoreM import Mathlib.Tactic.ToExpr -/-! # Script to check `undergrad.yaml`, `overview.yaml`, and `100.yaml` +/-! # Script to check `undergrad.yaml`, `overview.yaml`, `100.yaml` and `1000.yaml` This assumes `yaml_check.py` has first translated these to `json` files. -It verifies that the referenced declarations exist. +It verifies that the referenced declarations exist, and prints an error otherwise. -/ open IO.FS Lean Lean.Elab @@ -23,18 +23,15 @@ def readJsonFile (α) [FromJson α] (path : System.FilePath) : IO α := do let _ : MonadExceptOf String IO := ⟨throw ∘ IO.userError, fun x _ => x⟩ liftExcept <| fromJson? <|← liftExcept <| Json.parse <|← IO.FS.readFile path -def databases : List (String × String) := - ["undergrad", "overview", "100"].map fun dir => - (dir ++ ".json", - s!"Entries in `docs/{dir}.yaml` refer to declarations that don't exist. \ - Please correct the following:") +def databases : List String := ["undergrad", "overview", "100", "1000"] -def processDb (decls : ConstMap) : String × String → IO Bool -| (file, msg) => do - let lines := ← readJsonFile DBFile file - let missing := lines.filter (fun l => !(decls.contains l.2)) +def processDb (decls : ConstMap) : String → IO Bool +| file => do + let lines ← readJsonFile DBFile s!"{file}.json" + let missing := lines.filter (fun l ↦ !(decls.contains l.2)) if 0 < missing.size then - IO.println msg + IO.println s!"Entries in `docs/{file}.yaml` refer to {missing.size} declaration(s) that don't exist. \ + Please correct the following:" for p in missing do IO.println s!" {p.1}: {p.2}" IO.println "" @@ -43,9 +40,10 @@ def processDb (decls : ConstMap) : String × String → IO Bool return false unsafe def main : IO Unit := do + Lean.enableInitializersExecution CoreM.withImportModules #[`Mathlib, `Archive] (searchPath := compile_time_search_path%) (trustLevel := 1024) do - let decls := (←getEnv).constants - let results ← databases.mapM (fun p => processDb decls p) + let decls := (← getEnv).constants + let results ← databases.mapM (fun p ↦ processDb decls p) if results.any id then IO.Process.exit 1 diff --git a/scripts/merge-lean-testing-pr.sh b/scripts/merge-lean-testing-pr.sh new file mode 100755 index 0000000000000..9cd3685a83a41 --- /dev/null +++ b/scripts/merge-lean-testing-pr.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +PR_NUMBER=$1 +BRANCH_NAME="lean-pr-testing-$PR_NUMBER" + +git checkout nightly-testing +git pull + +if ! git merge origin/$BRANCH_NAME; then + echo "Merge conflicts detected. Resolving conflicts in favor of current version..." + git checkout --ours lean-toolchain lakefile.lean lake-manifest.json + git add lean-toolchain lakefile.lean lake-manifest.json +fi + +sed "s/$BRANCH_NAME/nightly-testing/g" < lakefile.lean > lakefile.lean.new +mv lakefile.lean.new lakefile.lean +git add lakefile.lean + +# Check for merge conflicts +if git ls-files -u | grep -q '^'; then + echo "Merge conflicts detected. Please resolve conflicts manually." + git status + exit 1 +fi + +if ! lake update; then + echo "Lake update failed. Please resolve conflicts manually." + git status + exit 1 +fi + +# Attempt to commit. This will fail if there are conflicts. +if git commit -m "merge $BRANCH_NAME"; then + echo "Merge successful." + exit 0 +else + echo "Merge failed. Please resolve conflicts manually." + git status + exit 1 +fi diff --git a/scripts/nolints.json b/scripts/nolints.json index a698a174e1354..58730127f796d 100644 --- a/scripts/nolints.json +++ b/scripts/nolints.json @@ -61,7 +61,6 @@ ["docBlame", "AffineMap.toFun"], ["docBlame", "AlgHom.toAddMonoidHom'"], ["docBlame", "AlgHom.toMonoidHom'"], - ["docBlame", "AlgebraCat.carrier"], ["docBlame", "Bifunctor.bimap"], ["docBlame", "Bimod.X"], ["docBlame", "Bimod.actLeft"], @@ -353,7 +352,6 @@ ["docBlame", "VectorPrebundle.pretrivializationAt"], ["docBlame", "VectorPrebundle.pretrivializationAtlas"], ["docBlame", "WithIdeal.i"], - ["docBlame", "WithZeroTopology.instHasContinuousInv₀"], ["docBlame", "WriterT.adapt"], ["docBlame", "WriterT.callCC"], ["docBlame", "WriterT.callCC'"], diff --git a/scripts/nolints_prime_decls.txt b/scripts/nolints_prime_decls.txt index 414151f344621..141e187da20d1 100644 --- a/scripts/nolints_prime_decls.txt +++ b/scripts/nolints_prime_decls.txt @@ -2563,7 +2563,7 @@ Matrix.cons_val_succ' Matrix.cons_val_zero' Matrix.det_apply' Matrix.det_units_conj' -Matrix.det_updateColumn_smul' +Matrix.det_updateCol_smul' Matrix.det_updateRow_smul' Matrix.diagonal_apply_ne' Matrix.diagonal_intCast' diff --git a/scripts/noshake.json b/scripts/noshake.json index 2ca0558661bde..acb992ed41e28 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -324,7 +324,8 @@ ["Mathlib.Algebra.MvPolynomial.CommRing", "Mathlib.Algebra.Polynomial.Basic"], "Mathlib.RingTheory.IntegralClosure.IsIntegral.Defs": ["Mathlib.Tactic.Algebraize"], - "Mathlib.RingTheory.Finiteness.Defs": ["Mathlib.Tactic.Algebraize"], + "Mathlib.RingTheory.Finiteness.Defs": + ["Mathlib.Data.Finsupp.Defs", "Mathlib.Tactic.Algebraize"], "Mathlib.RingTheory.Binomial": ["Mathlib.Algebra.Order.Floor"], "Mathlib.RingTheory.Adjoin.Basic": ["Mathlib.LinearAlgebra.Finsupp.SumProd"], "Mathlib.RepresentationTheory.FdRep": @@ -423,6 +424,7 @@ ["Mathlib.Tactic.CategoryTheory.Bicategory.Basic"], "Mathlib.Analysis.Normed.Operator.LinearIsometry": ["Mathlib.Algebra.Star.Basic"], + "Mathlib.Analysis.InnerProductSpace.PiL2": ["Mathlib.Util.Superscript"], "Mathlib.Analysis.InnerProductSpace.Basic": ["Mathlib.Algebra.Module.LinearMap.Basic"], "Mathlib.Analysis.Distribution.SchwartzSpace": ["Mathlib.Tactic.MoveAdd"], diff --git a/scripts/yaml_check.py b/scripts/yaml_check.py index 5d6ee74ddfa4f..7605122447a6d 100644 --- a/scripts/yaml_check.py +++ b/scripts/yaml_check.py @@ -1,7 +1,13 @@ """ -This file is copied from the mathlib3 file of the same name. -It reads in the three yaml files, and translates them to simpler json files that are easier to -process in Lean. +This file reads in the four yaml files, and translates them to simpler json files +that are easier to process in Lean. + +Usage: + python3 yaml_check.py <100.yaml> <1000.yaml> + +(Each is the path to a yaml file containing information about the respective class + of theorems. The order of these files is important.) + """ from typing import Dict, Optional, Union, Tuple, List import yaml @@ -32,17 +38,20 @@ def print_list(fn: str, pairs: List[Tuple[str, str]]) -> None: out.write(f'{id}\n{val.strip()}\n\n') hundred_yaml = sys.argv[1] -overview_yaml = sys.argv[2] -undergrad_yaml = sys.argv[3] +thousand_yaml = sys.argv[2] +overview_yaml = sys.argv[3] +undergrad_yaml = sys.argv[4] with open(hundred_yaml, 'r', encoding='utf8') as hy: hundred = yaml.safe_load(hy) +with open(thousand_yaml, 'r', encoding='utf8') as hy: + thousand = yaml.safe_load(hy) with open(overview_yaml, 'r', encoding='utf8') as hy: overview = yaml.safe_load(hy) with open(undergrad_yaml, 'r', encoding='utf8') as hy: undergrad = yaml.safe_load(hy) -hundred_decls:List[Tuple[str, str]] = [] +hundred_decls: List[Tuple[str, str]] = [] for index, entry in hundred.items(): title = entry['title'] @@ -53,6 +62,16 @@ def print_list(fn: str, pairs: List[Tuple[str, str]]) -> None: raise ValueError(f"For key {index} ({title}): did you mean `decl` instead of `decls`?") hundred_decls = hundred_decls + [(f'{index} {title}', d) for d in entry['decls']] +thousand_decls: List[Tuple[str, str]] = [] +for index, entry in thousand.items(): + title = entry['title'] + if 'decl' in entry: + thousand_decls.append((f'{index} {title}', entry['decl'])) + elif 'decls' in entry: + if not isinstance(entry['decls'], list): + raise ValueError(f"For key {index} ({title}): did you mean `decl` instead of `decls`?") + thousand_decls = thousand_decls + [(f'{index} {title}', d) for d in entry['decls']] + overview_decls = tiered_extract(overview) assert all(len(n) == 3 for n, _ in overview_decls) overview_decls = flatten_names(overview_decls) @@ -63,6 +82,8 @@ def print_list(fn: str, pairs: List[Tuple[str, str]]) -> None: with open('100.json', 'w', encoding='utf8') as f: json.dump(hundred_decls, f) +with open('1000.json', 'w', encoding='utf8') as f: + json.dump(thousand_decls, f) with open('overview.json', 'w', encoding='utf8') as f: json.dump(overview_decls, f) with open('undergrad.json', 'w', encoding='utf8') as f: diff --git a/scripts/zulip_emoji_merge_delegate.py b/scripts/zulip_emoji_merge_delegate.py index f31e66c7b506f..de3e5d3ca70c3 100644 --- a/scripts/zulip_emoji_merge_delegate.py +++ b/scripts/zulip_emoji_merge_delegate.py @@ -65,6 +65,7 @@ has_peace_sign = any(reaction['emoji_name'] == 'peace_sign' for reaction in reactions) has_bors = any(reaction['emoji_name'] == 'bors' for reaction in reactions) has_merge = any(reaction['emoji_name'] == 'merge' for reaction in reactions) + has_awaiting_author = any(reaction['emoji_name'] == 'writing' for reaction in reactions) match = pr_pattern.search(content) if match: print(f"matched: '{message}'") @@ -82,7 +83,9 @@ print('Removing bors') result = client.remove_reaction({ "message_id": message['id'], - "emoji_name": "bors" + "emoji_name": "bors", + "emoji_code": "22134", + "reaction_type": "realm_emoji", }) print(f"result: '{result}'") if has_merge: @@ -92,6 +95,14 @@ "emoji_name": "merge" }) print(f"result: '{result}'") + if has_awaiting_author: + print('Removing awaiting-author') + result = client.remove_reaction({ + "message_id": message['id'], + "emoji_name": "writing" + }) + print(f"result: '{result}'") + # applying appropriate emoji reaction print("Applying reactions, as appropriate.") @@ -107,6 +118,15 @@ "message_id": message['id'], "emoji_name": "peace_sign" }) + elif LABEL == 'labeled': + print('adding awaiting-author') + client.add_reaction({ + "message_id": message['id'], + "emoji_name": "writing" + }) + elif LABEL == 'unlabeled': + print('awaiting-author removed') + # the reaction was already removed. elif LABEL.startswith("[Merged by Bors]"): print('adding [Merged by Bors]') client.add_reaction({